自定义ViewPager切换动画

实现基础的ViewPager###

1.主布局文件activity_main.xml,一个用于放ViewPager的RelativeLayout容器,里面就是我们用于展示的ViewPager了。




    

        
        

    

这里有个需要注意的地方:RelativeLayout和ViewPager的clipChildren属性都需要设置为false,目的是让ViewPager左边右边的界面也显示出来,不然ViewPager只会显示中间ViewPager在布局上所占的那部分空间。如果不清楚直接看下图:

自定义ViewPager切换动画_第1张图片
clipChildren=“false”
自定义ViewPager切换动画_第2张图片
clipChildren=“true”

2.ViewPager的Adapter类,在构造函数中传入要显示的数据源,这里就是每个page上要显示的文本。在instantiateItem()方法中加载要显示的页面,找到其中的TextView,设置要显示的文本。至于这四个函数的作用可以参考ViewPager 详解(二)---详解四大函数

MyPagerAdapter.java

public class MyPagerAdapter extends PagerAdapter {
    private String[] mDatas;
    private Context mContext;

    public MyPagerAdapter(Context context,String[] mDatas) {
        this.mContext =context;
        this.mDatas = mDatas;
    }

    @Override
    public int getCount() {
        return mDatas.length;
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.view_pager_item,null);
        TextView tv = (TextView) view.findViewById(R.id.tv_text);
        tv.setText(mDatas[position]);
        container.addView(view);
        return view;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        View view = (View) object;
        container.removeView(view);
    }

3.ViewPager的每个界面布局view_pager_item.xml,就是一个Textview,没啥好说的。




    

4.MainActivity.java

public class MainActivity extends AppCompatActivity {

    private RelativeLayout rl_container;
    private ViewPager viewPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findId();
        initViewPager();
    }

    private void findId() {
        viewPager = (ViewPager) findViewById(R.id.view_pager);
        rl_container = (RelativeLayout) findViewById(R.id.rl_container);
    }

    private void initViewPager() {
        //创建数据源
        String[] stringArr = new String[8];
        for(int i=0;i

写到这里我们可以来运行一下,结果发现只有中间滑动有效果,而如果在两边滑动时,ViewPager是不会切换页面的。这是因为点击事件被容器RelativeLayout拦截了。加入下面的代码就能解决问题了。

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        ......
        initViewPager();
        
        rl_container.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return viewPager.dispatchTouchEvent(event);
            }
        });
    }

给RelativeLayout设置OnTouchListener使得当其接收到触摸事件时会将该事件转给ViewPager进行分发。这样就能让ViewPager处理左右两边的触摸事件了。

至此,一个简单的ViewPager就完成了,来看看效果。

PageTransformer###

这个类是我们实现自定义切换动画的核心。ViewPager有一个setPageTransformer()方法用于设置切换动画。goolgle官方提供了两个动画效果,DepthPageTransformer和ZoomOutPageTransformer,具体效果可以参考一下鸿洋大神的这篇博客Android 实现个性的ViewPager切换动画 实战PageTransformer(兼容Android3.0以下)。关于下面要讲到的position的意义,如果觉得博主讲的不清楚也可以参考这篇博客Android 自定义 ViewPager 打造千变万化的图片切换效果。

我们看到PageTransformer中要实现这样一个函数:

@Override
public void transformPage(View page, float position) {

 }  

解释一下,这里的page指的就是在滑动的页面,而position是指该页面的位置,用下面这张图解释:

自定义ViewPager切换动画_第3张图片
2017-02-26_195739.png

position取值可以看成该页面左上角的位置

  • 当position<-1的时候,表示该page处在当前显示页面的左边一个页面位置以外。
  • 当position=-1的时候,表示该page处在当前显示页面的左边一个页面位置,此时该页面的右上角就是当前显示页面的左上角。
  • 当position=0的时候,表示该page处在当前显示页面位置
  • 当position=1的时候,表示该page处在当前显示页面的右边一个页面位置,此时该页面的左上角就是当前显示页面的右上角。
  • 当position>1的时候,表示该page处在当前显示页面的右边一个页面位置以外。

举个栗子:


自定义ViewPager切换动画_第4张图片

上图中page0的position为-2,page1为-1,page2为当前显示页面,position为0,page3为1,page4为2。在page2往左边划的过程中,page2的position值会从1变到0,同理,page3的position值会从1变到0。

有了这样的一个position值,便可以开始制作动画了。
制作动画前先看一下要用到的几个函数(这里可以参考这篇博客【Android开发】View的平移、缩放、旋转以及位置、坐标系)

  • page.setTranslationX(float x)
    page.setTranslationY(float y)

    这两个函数用于设置page在x,y方向的位移
  • page.setScaleX(float scaleX);
    page.setScaleY(float scaleY);

    这两个函数用于设置page在x,y方向的放缩比例
  • page.setAlpha(float alpha)
    这个函数用于设置page的透明度
  • page.setRotation(float rotation)
    page.setRotationX(float rotationX)
    page,setRotationY(float rotationY)

    这三个函数用于设置page在x,y,z轴方向的旋转角度
  • page.setPivotX(float pivotX)
    page.setPivotY(float pivotY)

    这两个函数是最重要的,也相对比较难理解,用于设置view缩放和旋转的锚点坐标,正常情况下page的锚点在正中心位置
自定义ViewPager切换动画_第5张图片

锚点的位置,将决定page缩放后所在的位置。因为默认是中心坐标,所以缩放后,其结果在水平中心位置或垂直中心位置。但是,如果锚点的位置变了,那么View缩放后的位置也将发生变化。
旋转时,将会以锚点所在的轴线为轴进行旋转,比如:

  • 不同锚点setRotation(90)的效果(红点为锚点位置)
自定义ViewPager切换动画_第6张图片
2017-02-26_205747.png
  • 不同锚点setRotationY(45)的效果(红点为锚点位置)


    自定义ViewPager切换动画_第7张图片
    setRotationY(45)
自定义ViewPager切换动画_第8张图片
注意两张page0的区别

了解以上几个函数的效果就可以动手写动画了,所谓动画无非就是像总结一个函数一样,对于任意的position能找到一个特定的属性与之对应,这个值可以是透明度、旋转角度、位移等等。
举个栗子,如果我们想实现下面这种动画,只要找出这样一个对应的函数就可以了。

** 总结规律:**

  • position<=-1时, translationY = 100
  • -1
  • position=0时, translationY = 0
  • 0
  • position>=1时, translationY =100;

我们还可以根据上面的规律画成图像:


自定义ViewPager切换动画_第9张图片
translationY对应的函数图像

有了这样清晰的概念写出动画就不是什么难事了。下面看源码:

@Override
public void transformPage(View page, float position) {
    page.setPivotY(page.getHeight()/2);
    float maxTransform = page.getHeight()/4;
    if (position <= -1)
    { // [-Infinity,-1)
        // This page is way off-screen to the left.
        page.setTranslationY(maxTransform);
    } else if (position < 1)
    { // [-1,1]
        // Modify the default slide transition to shrink the page as well
        if (position < 0)//[0,-1]
        {
            page.setTranslationY(-position * maxTransform);
        } else//[1,0]
        {
            page.setTranslationY(position * maxTransform);
        }
    } else
    { // (1,+Infinity]
        // This page is way off-screen to the right.
        page.setTranslationY(maxTransform);
    }
}

再看个复杂点的

@Override
public void transformPage(View page, float position) {
    page.setPivotY(page.getHeight()/2);
    float maxRotate = 35f;
    float minScale = 0.8f;
    float maxTranslationX = page.getWidth()/5;
    if (position <= -1)
    { // [-Infinity,-1)
        // This page is way off-screen to the left.
        page.setRotationY(maxRotate);
        page.setPivotX(0);
        page.setScaleX(minScale);
        page.setScaleY(minScale);
        page.setTranslationX(maxTranslationX);
    } else if (position < 1)
    { // [-1,1]
        page.setRotationY(-position * maxRotate);
        if (position < 0)//[0,-1]
        {
            page.setPivotX(0);
            page.setScaleX(1 + position * (1-minScale));
            page.setScaleY(1 + position * (1-minScale));
            page.setTranslationX(-position * maxTranslationX);
        } else//[1,0]
        {
            page.setPivotX(page.getWidth());
            page.setScaleX(1 - position * (1-minScale));
            page.setScaleY(1 - position * (1-minScale));
            page.setTranslationX(-position * maxTranslationX);
        }
    } else
    { // (1,+Infinity]
        // This page is way off-screen to the right.
        page.setRotationY(-1 * maxRotate);
        page.setPivotX(page.getWidth());
        page.setScaleX(minScale);
        page.setScaleY(minScale);
        page.setTranslationX(-maxTranslationX);
    }
}

最后啰嗦两句###

总算写完了,第一次写博客,找各种各样的工具花了好长时间,录屏使用的是手机app录屏专家,再传到电脑上使用Free Video to GIF Converter转成gif,断断续续花了一晚上。如果大家有好的录屏软件推荐麻烦给博主留个言,谢谢了!

你可能感兴趣的:(自定义ViewPager切换动画)