Android 实现个性的ViewPager切换动画 实战PageTransformer(兼容Android3

}

});

}

private void initData()

{

for (int imgId : mImgIds)

{

ImageView imageView = new ImageView(getApplicationContext());

imageView.setScaleType(ScaleType.CENTER_CROP);

imageView.setImageResource(imgId);

mImageViews.add(imageView);

}

}

}

好了,这样一个传统ViewPager就实现了~~大家对上面代码应该不会有任何陌生的感觉运行效果也不用贴图了,大家肯定知道~

3、PageTransformer


ViewPager有个方法叫做:

setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) 用于设置ViewPager切换时的动画效果,并且google官方还给出了两个示例。

只需要在上述代码中调用setPageTransformer即可添加切换动画效果~~下面演示google的两个PageTransformer的代码,以及运行效果。

1、DepthPageTransformer

public class DepthPageTransformer implements ViewPager.PageTransformer {

private static final float MIN_SCALE = 0.75f;

public void transformPage(View view, float position) {

int pageWidth = view.getWidth();

if (position < -1) { // [-Infinity,-1)

// This page is way off-screen to the left.

view.setAlpha(0);

} else if (position <= 0) { // [-1,0]

// Use the default slide transition when moving to the left page

view.setAlpha(1);

view.setTranslationX(0);

view.setScaleX(1);

view.setScaleY(1);

} else if (position <= 1) { // (0,1]

// Fade the page out.

view.setAlpha(1 - position);

// Counteract the default slide transition

view.setTranslationX(pageWidth * -position);

// Scale the page down (between MIN_SCALE and 1)

float scaleFactor = MIN_SCALE

  • (1 - MIN_SCALE) * (1 - Math.abs(position));

view.setScaleX(scaleFactor);

view.setScaleY(scaleFactor);

} else { // (1,+Infinity]

// This page is way off-screen to the right.

view.setAlpha(0);

}

}

}

调用代码:

mViewPager.setPageTransformer(true, new DepthPageTransformer());

效果:

2、ZoomOutPageTransformer

package com.zhy.view;

import android.annotation.SuppressLint;

import android.support.v4.view.ViewPager;

import android.util.Log;

import android.view.View;

public class ZoomOutPageTransformer implements ViewPager.PageTransformer

{

private static final float MIN_SCALE = 0.85f;

private static final float MIN_ALPHA = 0.5f;

@SuppressLint(“NewApi”)

public void transformPage(View view, float position)

{

int pageWidth = view.getWidth();

int pageHeight = view.getHeight();

Log.e(“TAG”, view + " , " + position + “”);

if (position < -1)

{ // [-Infinity,-1)

// This page is way off-screen to the left.

view.setAlpha(0);

} else if (position <= 1) //a页滑动至b页 ; a页从 0.0 -1 ;b页从1 ~ 0.0

{ // [-1,1]

// Modify the default slide transition to shrink the page as well

float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));

float vertMargin = pageHeight * (1 - scaleFactor) / 2;

float horzMargin = pageWidth * (1 - scaleFactor) / 2;

if (position < 0)

{

view.setTranslationX(horzMargin - vertMargin / 2);

} else

{

view.setTranslationX(-horzMargin + vertMargin / 2);

}

// Scale the page down (between MIN_SCALE and 1)

view.setScaleX(scaleFactor);

view.setScaleY(scaleFactor);

// Fade the page relative to its size.

view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE)

/ (1 - MIN_SCALE) * (1 - MIN_ALPHA));

} else

{ // (1,+Infinity]

// This page is way off-screen to the right.

view.setAlpha(0);

}

}

}

调用代码:

mViewPager.setPageTransformer(true, new ZoomOutPageTransformer());

效果:

效果图都是google官网上的,我们的测试图会在兼容3.0以下贴出来,不然就重复了~~

为ViewPager添加切换就一行代码是不是很happy,可惜是不兼容3.0以下的版本的,该方法的注释上写到:

setting a PageTransformer prior to Android 3.0 (API 11) will have no effect 在3.0之前的版本设置此方法是没有效果的,那么下面我们就看如何让其兼容3.0以下版本。

3、版本的向下兼容

=========

1、不兼容的原因


首先看下为什么不兼容,3.0以下呢?

看上面的两个示例代码,代码中View的动画使用的是属性动画,而属性动画是3.0才推出的,那么这么写肯定是不兼容3.0以下了~

那么我们首先引入nineoldandroids,让动画先能在3.0以下跑再说:

修改DepthPageTransformer

package com.zhy.view;

import com.nineoldandroids.view.ViewHelper;

import android.annotation.SuppressLint;

import android.support.v4.view.ViewPager;

import android.view.View;

public class DepthPageTransformer implements ViewPager.PageTransformer

{

private static final float MIN_SCALE = 0.75f;

public void transformPage(View view, float position)

{

int pageWidth = view.getWidth();

if (position < -1)

{ // [-Infinity,-1)

// This page is way off-screen to the left.

// view.setAlpha(0);

ViewHelper.setAlpha(view, 0);

} else if (position <= 0)// a页滑动至b页 ; a页从 0.0 -1 ;b页从1 ~ 0.0

{ // [-1,0]

// Use the default slide transition when moving to the left page

// view.setAlpha(1);

ViewHelper.setAlpha(view, 1);

// view.setTranslationX(0);

ViewHelper.setTranslationX(view, 0);

// view.setScaleX(1);

ViewHelper.setScaleX(view, 1);

// view.setScaleY(1);

ViewHelper.setScaleY(view, 1);

} else if (position <= 1)

{ // (0,1]

// Fade the page out.

// view.setAlpha(1 - position);

ViewHelper.setAlpha(view, 1 - position);

// Counteract the default slide transition

// view.setTranslationX(pageWidth * -position);

ViewHelper.setTranslationX(view, pageWidth * -position);

// Scale the page down (between MIN_SCALE and 1)

float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - position);

// view.setScaleX(scaleFactor);

ViewHelper.setScaleX(view, scaleFactor);

// view.setScaleY(1);

ViewHelper.setScaleY(view, scaleFactor);

} else

{ // (1,+Infinity]

// This page is way off-screen to the right.

// view.setAlpha(0);

ViewHelper.setAlpha(view, 1);

}

}

}

很简单,把所有属性动画换成ViewHelper去设置就好了。现在我们去3.0以下的机子上去运行,发现还是没有效果~~~

为什么呢?

我们再去看看setPageTransformer的源码:

public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) {

if (Build.VERSION.SDK_INT >= 11) {

final boolean hasTransformer = transformer != null;

final boolean needsPopulate = hasTransformer != (mPageTransformer != null);

mPageTransformer = transformer;

setChildrenDrawingOrderEnabledCompat(hasTransformer);

if (hasTransformer) {

mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD;

} else {

mDrawingOrder = DRAW_ORDER_DEFAULT;

}

if (needsPopulate) populate();

}

}

终于发现原因了,原来在此方法内部判断了如果是11以上的版本才让动画生效~~

那么,没办法了,如果想兼容,必须修改ViewPager的源码了~~

2、完美向下兼容


我们将ViewPager的源码拷贝一份至我们的项目中,修改名称为ViewPagerCompat;然后注释掉SDK版本判断那一句

public class ViewPagerCompat extends ViewGroup {

public void setPageTransformer(boolean reverseDrawingOrder, ViewPager.PageTransformer transformer) {

// if (Build.VERSION.SDK_INT >= 11)

{

final boolean hasTransformer = transformer != null;

final boolean needsPopulate = hasTransformer != (mPageTransformer != null);

mPageTransformer = transformer;

setChildrenDrawingOrderEnabledCompat(hasTransformer);

if (hasTransformer) {

mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD;

} else {

mDrawingOrder = DRAW_ORDER_DEFAULT;

}

if (needsPopulate) populate();

}

}

}

注意,所有的PageTransformer使用ViewPager.PageTransformer

然后我们把项目中的ViewPager改为ViewPagerCompat;记得修改布局文件,以及MainActivity中的ViewPager为ViewPagerCompat

我们在2.3.3的模拟器上测试下效果:

可以看到,我们的切换动画完美的运行在2.3.3的机器上~~so happy 没有ViewPager源码的童鞋不要紧,我会在文末的源码下载中加入ViewPager源码,让你可以尽情去测试

当然了,仅仅是兼容当然不能满足我们的好奇心,难道我们做到了兼容,还只能使用Google给的示例动画么我们强大的创新呢下面带领大家分析setPageTransformer方法,然后设计一个个性的动画切换效果

4、自定义PageTransformer实现个性切换动画

============================

public interface PageTransformer {

/**

  • Apply a property transformation to the given page.

  • @param page Apply the transformation to this page

  • @param position Position of page relative to the current front-and-center

  •             position of the pager. 0 is front and center. 1 is one full
    
  •             page position to the right, and -1 is one page position to the left.
    

*/

public void transformPage(View page, float position);

}

可以看到该接口只有一个方法,第一个是我们的view,第二个是position~~

当我们滑动时:会打印出当然ViewPager中存活的每个View以及它们的position的变化注意是每一个,所以建议别只log position,不然你会觉得莫名其妙的输出

position的可能性的值有,其实从官方示例的注释就能看出:

[-Infinity,-1)  已经看不到了

(1,+Infinity] 已经看不到了

[-1,1]

重点看[-1,1]这个区间 , 其他两个的View都已经看不到了~~

假设现在ViewPager在A页现在滑出B页,则:

A页的position变化就是( 0, -1]

B页的position变化就是[ 1 , 0 ]

知道了我们滑动时position的变化~~那么就开始设计我们的个性的切换效果;

官方给的例子,有变化透明度、偏移量、缩放的,我们准备来个不一样的,我们变化角度,即rotation;

大概的效果是这样的:

下面我们分析代码:

我们设置View的旋转中心为:

ViewHelper.setPivotX(view, view.getMeasuredWidth() * 0.5f);

ViewHelper.setPivotY(view, view.getMeasuredHeight());

依然是ViewPager在A页现在滑出B页

那么A页应当在滑动过程中0度到-20度的偏移,B页应当在滑动过程中+20度到0度的偏移

结合

A页的position变化就是( 0, -1]

B页的position变化就是[ 1 , 0 ]

那么旋转的角度即:mRot = (20 * position); A页 mRot :0 ,~ -20 ; B页 mRot :20 ~ 0  ;

瞬间觉得好简单:

完整代码:

package com.zhy.view;

import com.nineoldandroids.view.ViewHelper;

import android.annotation.SuppressLint;

import android.support.v4.view.ViewPager;

import android.util.Log;

import android.view.View;

public class RotateDownPageTransformer implements ViewPager.PageTransformer

{

private static final float ROT_MAX = 20.0f;

private float mRot;

public void transformPage(View view, float position)

{

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

我这里整理了一份完整的学习思维以及Android开发知识大全PDF。

当然实践出真知,即使有了学习线路也要注重实践,学习过的内容只有结合实操才算是真正的掌握。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

[外链图片转存中…(img-KN8vHLJo-1713116907407)]

[外链图片转存中…(img-VI7GMfb5-1713116907407)]

[外链图片转存中…(img-vTGU0xeL-1713116907408)]

[外链图片转存中…(img-xzvx2Vz1-1713116907408)]

[外链图片转存中…(img-XdOvN3Fg-1713116907408)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

我这里整理了一份完整的学习思维以及Android开发知识大全PDF。

[外链图片转存中…(img-pyCwrMjw-1713116907409)]

当然实践出真知,即使有了学习线路也要注重实践,学习过的内容只有结合实操才算是真正的掌握。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值