ViewPager进阶篇——>转场特效

在开始本文之前我们得知道什么是专场特效,有什么效果。

例1

先上一张效果图:
演示1

今天我们就来实现这个效果并且在做两个练习。


对于ViewPager基本使用比较简单这里不再说明了。
开始讲解我们今天的主题。
翻看源码:
我们发现接口PageTransformer。顾名思义实现该接口可以控制ViewPager中item view的滑动效果。

 /**
     * A PageTransformer is invoked whenever a visible/attached page is scrolled.
     * This offers an opportunity for the application to apply a custom transformation
     * to the page views using animation properties.
     *
     * <p>As property animation is only supported as of Android 3.0 and forward,
     * setting a PageTransformer on a ViewPager on earlier platform versions will
     * be ignored.</p>
     */
    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.
         */
        void transformPage(@NonNull View page, float position);
    }

方法也比较简单。
也就是说当ViewPager中的View滑动时,会触发PageTransformer调用transformPage方法。PageTransformer 支持用户通过动画属性自定义页面滑动效果。transformPage(View page, float position)方法中两个参数分别是当前的View和当前Page的“坐标位置”,对于position也是重点不好理解,接下来我将用例子来说明position是什么。

我们来重写ViewPager调用setPageTransformer来时先刚才的效果图。
实现原理:
在左滑过程中当前Page1正常左移,下一页Page2以0.5到1的比例缩放透明度变化直至恢复透明度和缩放比例恢复原状。
向右滑动过程中当前Page2以1到0.5的比例缩放且透明度变化并且位移至ViewPager最左端。上一页Page1正常右移直至覆盖恢复原状。

代码如下(填充ViewPager比较简单省略):

/**
 * @description:水平切换 上下切换
 * @Author MRyan
 * @Date 2020/3/20 14:53
 * @Version 1.0
 */
public class CustomReaderViewPager extends ViewPager {
    public CustomReaderViewPager(Context context) {
        this(context, null);
    }

    public CustomReaderViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        setReadEffect();
    }


    @SuppressLint("ClickableViewAccessibility")
    private void setReadEffect() {
        setPageTransformer(true, new PageTransformer() {//reverseDrawingOrder 返回True前面的视图可以遮住后面的视图
            private float MIN_SCALE = 0.5f;//初始

            @Override
            public void transformPage(View page, float position) {
                Log.e("position",page.toString()+position+"");
                int pageWidth = page.getWidth();
                if (position <= 0) { //不缩放不移动  左滑时当前的View position=(0->-1] ||右滑时前一个View position=(0->-1]
                    page.setTranslationX(0);
                    page.setScaleX(1);
                    page.setScaleY(1);
                } else if (position <= 1) { // (0,1]  左滑时后一个View position=[1->0) ||右滑时当前View position=(0->1]
                    float SCALE = 0.5f - position / 2; //左滑时SCALE从0变为0.5 右滑时从0.5变为0
                    page.setScaleX(MIN_SCALE + SCALE);
                    page.setScaleY(MIN_SCALE + SCALE);
                    page.setAlpha(MIN_SCALE + SCALE);
                    page.setTranslationX(pageWidth *-position); //左移
                  /*  Log.e("pageWidth",pageWidth *-position+"");*/
                } else {//右滑时后一个View position=[1->+无穷) || 左滑时前一个View position=(-无穷->-1]
                    page.setTranslationX(pageWidth);//移出右端到屏幕外侧
                }
            }
        });
    }
}

相信你看到这里已经懵了,position到底是什么代表什么意思。别急我们打印下Log信息来仔细研究。

我们设第一个界面为Page1 ID:255b1d6
设第二个界面为Page2 ID: b68c344
设第三个界面Page3 ID: b4f84e0

当我们左滑ViewPager第一次时 打印Log:

1

2

根据ID我们可知Page1的postion变化趋势,我们发现postion的值由0逐渐减少变为-1 记做(0->-1] 不等于0可以等于-1。

3

4

根据ID我们可知Page2的postion变化趋势,我们发现postion的值由1逐渐变为0 记做[1,0)

左滑 第一次:
ID: 255b1d6   0->-1 当前View(Page1)
ID: b68c344   1->0  后一个View (Page2)
结束显示Page2

我们左滑一次的过程实际上就是Page1(当前页面)向左滑动直至消失,Page2(下一页)出现直至变为当前页。

再次左滑ViewPager 打印Log:

5

6

根据ID我们可知Page3的postion变化趋势,我们发现postion的值由1逐渐变为0 记做[1,0)
根据ID我们可知Page2的postion变化趋势,我们发现postion的值由0逐渐变为-1 记做(0,-1]
根据ID我们可知Page1的postion变化趋势,我们发现postion的值由-1逐渐变为-2 记做[-1,-2]

左滑 第二次:
ID: 255b1d6   -1->-2  前一个View(Page1)
ID: b68c344    0->-1   当前View(Page2)
ID: b4f84e0    1->0  后一个View(Page3)  
结束显示Page3

我们再次左滑的过程其实就是Page2作为当前页面向左滑动直至消失,Page3出现直至成为当前页。

同理我们也可以推导出第三次左滑postion的变化趋势:

ID: b68c344    -1->-2   前一个View(Page2)
ID: b4f84e0    0->-1 当前View(Page3)  
ID: ?    1->0 后一个View(Page4)  

因此我们得到如下结论:

  前一个view的position变化   当前view的position变化      后一个view的position变化
     -1 ----> 0	            0-------->1	             1 ----> +∞   (当前view右滑时)
    - 1---->-∞	            0 -----> -1	             1 ------->0    (当前view左滑时)

由此我们就可以更好的理解postion了。

我们趁热打铁继续做练习。

例2

实现效果:
演示2

实现原理:
一屏多个视图滚动,且当前页面缩放比例正常且透明度正常(正常为1),两侧缩放且透明度减少。在滑动的过程中缩放比例和透明度也是变化的。

实现:
首先我们需要在自定义ViewPager和自身布局中添加如下代码:
android:clipChildren=“false”
设置屏多个视图滚动 在控件和根ViewGroup一起设置

在Activity中设置左右宽距和预加载数

mViewPage2.setCurrentItem(1);    //设置当前显示哪个子元素
mViewPage2.setPageMargin(10);//设置左右相距
mViewPage2.setOffscreenPageLimit(3);//设置预加载的页数 默认为1

接着使我们的自定义ViewPager
代码如下:

/**
 * @description:水平切换一屏多个视图滚动
 * @Author MRyan
 * @Date 2020/3/20 14:53
 * @Version 1.0
 */
public class CustomReaderViewPager2 extends ViewPager {
    public CustomReaderViewPager2(Context context) {
        this(context, null);
    }

    public CustomReaderViewPager2(Context context, AttributeSet attrs) {
        super(context, attrs);
        setReadEffect();
    }


    @SuppressLint("ClickableViewAccessibility")
    private void setReadEffect() {
        setPageTransformer(true, new PageTransformer() {//reverseDrawingOrder 返回True前面的视图可以遮住后面的视图
            private float MIN_SCALE = 0.8f;//初始
            private float MIN_ALPHA = 0.3f;

            @Override
            public void transformPage(View page, float position) {
                float scaleFactor = Math.max(MIN_ALPHA, 1 - Math.abs(position));//[1->0.3] or [0.3->1]
                if (position < -1 || position > 1) {//前一个或者后一个 大小缩小0.5并且透明度减少0.5
                    page.setScaleX(MIN_SCALE);
                    page.setScaleY(MIN_SCALE);
                    page.setAlpha(scaleFactor);
                } else if (position <= 1) {
                    if (position < 0) {//右滑时前一个View position=[-1->0) ||左滑时当前View position=(0->1]
                        float scaleX = 1 + 0.2f * position;// 右滑时前一个View scaleX=0.8->1 || 左滑当前View scaleX=1->0.8
                        page.setScaleX(scaleX);
                        page.setScaleY(scaleX);
                    } else { //右滑当前View position=(0->1]
                        float scaleX = 1 - 0.2f * position;
                        page.setScaleX(scaleX);
                        page.setScaleY(scaleX);
                    }
                    page.setAlpha(scaleFactor);
                }
            }
        });
    }
}

代码中有详细解释,这里就不在说明了。

例3

实现效果:
演示3

实现原理:
page.setPivotX(float pivotX); 设置View的X轴支点,影响视图的旋转和缩放效果。
page.setPivotY(float pivotY); 设置View的Y轴支点,影响视图的旋转和缩放效果。
page.setRotationY(float rotationY); 设置View绕Y轴旋转的角度。

代码如下:

/**
 * @description:立体旋转
 * @Author MRyan
 * @Date 2020/3/20 14:53
 * @Version 1.0
 */
public class CustomReaderViewPager3 extends ViewPager {
    public CustomReaderViewPager3(Context context) {
        this(context, null);
    }

    public CustomReaderViewPager3(Context context, AttributeSet attrs) {
        super(context, attrs);
        setReadEffect();
    }


    @SuppressLint("ClickableViewAccessibility")
    private void setReadEffect() {
        setPageTransformer(true, new PageTransformer() {//reverseDrawingOrder 返回True前面的视图可以遮住后面的视图
            private float maxRotate = 90f; // 最大旋转角度
            @Override
            public void transformPage(View page, float position) {

                if (position < -1){
                    page.setPivotX(page.getWidth());
                    page.setPivotY(page.getHeight() / 2);
                    page.setRotationY(-maxRotate);
                }else if(position < 0){
                    page.setPivotX(page.getWidth() * (0.5f + 0.5f * (- position))); // X轴支点坐标变化范围[page.getWidth()/2, page.getWidth()]
                    page.setPivotY(page.getHeight() / 2);
                    page.setRotationY(maxRotate * position);
                }else if(position <= 1){
                    page.setPivotX(page.getWidth() * 0.5f * (1 - position)); // // X轴支点坐标变化范围[0, page.getWidth()/2]
                    page.setPivotY(page.getHeight() / 2);
                    page.setRotationY(maxRotate * position);
                }else{
                    page.setPivotX(0);
                    page.setPivotY(page.getHeight() / 2);
                    page.setRotationY(maxRotate);
                }
            }
        });
    }
}

到这里本文就结束了,可以自行扩展实现更多有趣的动画。

附上项目链接:
项目链接

个人博客:个人博客

发布了7 篇原创文章 · 获赞 1 · 访问量 123

猜你喜欢

转载自blog.csdn.net/qq_35416214/article/details/104999647
今日推荐