Android - ViewPager进阶篇之转场特效

作者: 梦想编织者灬小楠 | 来源:发表于2016-08-25 18:11 被阅读838次

    一.使用最简单的方式创建Android应用引导页(效果如下)

    my_view_pager.gif

    该引导仅需要一个ViewPager和一个ViewPager适配器即可完成。

    接下来,小编将从零开始讲解该引导如何实现,准备好了没O(∩_∩)O~,小司机要开车了...

    1.首先,为我们的GuideActivity创建一个布局文件(非常简单的布局)。

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <android.support.v4.view.ViewPager
            android:id="@+id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    
    </FrameLayout>
    

    2.接下来,完成GuideActivity(引导活动页面)。

    public class GuideActivity extends AppCompatActivity {
    
        private ViewPager mViewPager;
        private ViewPagerAdapter mViewPagerAdapter; // ViewPager适配器
        private int[] images; // 图片资源引用数组(填充引用图片的Id)
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            initToolbar(); // 初始化标题栏
            initView(); // 初始化视图
            initData(); // 初始化数据
        }
    
        /**
         * 初始化标题栏
         */
        private void initToolbar() {
            getSupportActionBar().hide(); // 隐藏标题栏
        }
    
        /**
         * 初始化视图
         */
        private void initView() {
            mViewPager = (ViewPager) findViewById(R.id.viewpager);
        }
    
        /**
         * 初始化数据
         */
        private void initData() {
            images = new int[]{R.mipmap.guide_page_one, R.mipmap.guide_page_two, R.mipmap.guide_page_three, R.mipmap.guide_page_four};
            mViewPagerAdapter = new ViewPagerAdapter(GuideActivity.this, images);
            mViewPager.setAdapter(mViewPagerAdapter);
        }
    }
    

    图片资源需要各位自己准备,小编就不提供了...O(∩_∩)O~

    我们的GuideActivity只是完成了一部分,因为ViewPagerAdapter我们还没有构建,别急...接下来就是它了...

    3.最后,构建ViewPager的适配器ViewPagerAdapter。

    /**
     * @ClassName: ViewPagerAdapter
     * @Description: ViewPager适配器
     * @Author Wangnan
     * @Date 2016/8/25
     */
    public class ViewPagerAdapter extends PagerAdapter {
    
        private Context mContext;
        private int[] images; // 图片资源引用数组
    
        public ViewPagerAdapter(Context context, int[] datas){
            images = datas;
            mContext = context;
        }
    
        /**
         * 获取数据(图片)数量
         * @return
         */
        @Override
        public int getCount() {
            return images.length;
        }
    
        /**
         * 当前View是否是instantiateItem中返回的对象
         * @param view 当前view
         * @param object 由instantiateItem()方法返回的对象
         * @return
         */
        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }
    
        /**
         * 初始化Item并向页面添加
         * @param container ViewPager
         * @param position 要实例化item对应的页面位置
         * @return
         */
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            ImageView mImageView = createImageView(mContext, position);
            container.addView(mImageView);
            return mImageView;
        }
    
        /**
         * 移除ViewPager中的Item
         * @param container viewpager
         * @param position 要移除页面的位置
         * @param object 要移除页面的对象
         */
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View)object);
        }
    
        /**
         * 创建ImageView
         * @param mContext
         * @param position
         * @return imageView
         */
        private ImageView createImageView(Context mContext, int position) {
            ImageView imageview = new ImageView(mContext);
            ViewPager.LayoutParams layoutParams = new ViewPager.LayoutParams(); // 等价于ViewGroup.LayoutParams(FILL_PARENT, FILL_PARENT)
            imageview.setLayoutParams(layoutParams); // 设置ImageView充满父容器
            imageview.setImageResource(images[position]); // 设置ImageView的显示图片
            imageview.setScaleType(ImageView.ScaleType.CENTER_CROP); // 设置ImageView缩放样式
            return imageview;
        }
    }
    

    这段代码可能对于初学者来讲很难理解,但小编已经做了很详细的解释。另外,小编仅教给大家如何使用,如果大家想要理解这些方法的调用原理,可以去查阅PagerAdapter的相关源码...

    二.使用PageTransformer打造炫酷翻转动画

    1.首先来看下Google为我们提供的样例DepthPageTransformer(下图为运行效果)

    gif_my_viewpage1.gif

    是不是感觉很神奇,接下来我们就看看如何使用PageTransformer实现这种效果...

    (1).创建DepthPageTransformer(深度效果页面转换器)

    /**
     * @ClassName: DepthPageTransformer
     * @Description: 深度效果页面转换器
     * @Author Wangnan
     * @Date 2016/8/25
     */
    public class DepthPageTransformer implements ViewPager.PageTransformer{
    
        private static final float MIN_SCALE = 0.75F; // 最小缩放比例
        @Override
        public void transformPage(View page, float position) {
            if(position < -1){ // [负无穷,-1):当前页面已经滑出左边屏幕,我们已经看不到了
                page.setAlpha(0F);
            } else if (position <= 0){ // [-1, 0]:当前页面向左画出,已远离中心位置,但还未滑出左屏幕
                page.setAlpha(1F);
                page.setTranslationX(0F);
                page.setScaleX(1F);
                page.setScaleY(1F);
            } else if (position <= 1){ // (0,1]:下一页面已经进入屏幕,但还在进入并未到达中间位置
                page.setAlpha(1 - position);
                page.setTranslationX(page.getWidth() * -position);
                float scale = MIN_SCALE + (1 - MIN_SCALE) * (1 - position);
                page.setScaleX(scale);
                page.setScaleY(scale);
            } else { // (1, 正无穷]:下一页面还未进入屏幕
                page.setAlpha(0F);
            }
        }
    }
    

    小编对Google提供的样例进行了简单的说明...里面涉及到一些View的样式设置和偏移计算,可能新手朋友们有些难以理解,这里小编进行下详细的说明...老司机们可略过...O(∩_∩)O~

    • 当新页面还未进入屏幕的之前,我们使用page.setAlpha(0F),使新页面View保持透明...

    • 当新页面正在进入屏幕时:

    • page.setAlpha(1 - position),使新页面逐渐变得可见;

    • page.setTranslationX(page.getWidth() * -position),使新页面的X轴的偏移量从负的屏幕宽度变为0(即View从左向右平移),因为新页面又是从右向左滑入的,这两种滑动效果在视觉上抵消了...我们会感觉到页面没有出现过平移;

    • page.setScaleX(scale)和page.setScaleY(scale)设置X轴方向和Y轴方向的页面缩放,从新页面进入的角度看页面是从原页面大小的0.75倍增加到1倍...scale的范围是[0.75,1],scale的计算就不再细说了...

    • 当旧页面向左滑出还未出边界时:

    • page.setAlpha(1F); 保持透明度完全可见

    • page.setTranslationX(0F); 保持X轴的偏移量为0

    • page.setScaleX(1F); 保持X轴方向缩放为视图原大小

    • page.setScaleY(1F);保持Y轴方向缩放为视图原大小

    • 当旧页面向左滑出左边界时,我们已经看不到该视图了,page.setAlpha(0F),使滑出去的旧页面View保持透明...

    (2).说了这么多,如何使用DepthPageTransformer呢?

    别担心!仅需一行代码...我们在刚写完的GuideActivty的initData方法最后添加一行代码(如下图所示):

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

    public class GuideActivity extends AppCompatActivity {
    
        ......
    
        /**
         * 初始化数据
         */
        private void initData() {
            images = new int[]{R.mipmap.guide_page_one, R.mipmap.guide_page_two, R.mipmap.guide_page_three, R.mipmap.guide_page_four};
            mViewPagerAdapter = new ViewPagerAdapter(GuideActivity.this, images);
            mViewPager.setAdapter(mViewPagerAdapter);
            mViewPager.setPageTransformer(true, new DepthPageTransformer());
        }
    }
    

    这样,我们的代码就完成了,上图的效果就出来了...

    接下来我们简单介绍一下ViewPager的setPageTransformer方法。

    setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer)

    方法作用:允许应用程序为每一个页面自定义属性转换,重写默认的滑动外观。(注:API>=11才可使用)

    第2个参数(transformer):传入自定义PageTransformer,修改每一个页面的动画属性。

    第1个参数(reverseDrawingOrder):是否反转绘制顺序。

    false(正常顺序 - first to last)从第一页开始绘制至最后一页

    true(反转顺序 - last to first)从最后一页开始绘制至第一页

    是不是好奇我们传true或false有何区别?

    如果传入false,即mViewPager.setPageTransformer(false, new DepthPageTransformer());后面页面是后绘制的,所以后页面的View悬浮在前一页面的View之上,直白点讲,前面的视图无法遮住后面的视图,滑动效果如下图所示:

    gif_my_viewpager2.gif

    如果传入true,即mViewPager.setPageTransformer(true, new DepthPageTransformer());前面页面是后绘制的,所以前面页面的View悬浮在后一页面的View之上,直白点讲,前面的视图可以遮住后面的视图,效果如下图所示

    gif_my_viewpage1.gif

    2.自定义自己的PageTransformer

    我们仿照Google提供的样例,写一个旋转的视图切换效果,这次先上代码,再给大家看效果。

    1.定义旋转页面转换器RotatePageTransformer

    /**
     * @ClassName: RotatePageTransformer
     * @Description: 旋转页面转换器
     * @Author Wangnan
     * @Date 2016/8/25
     */
    public class RotatePageTransformer implements ViewPager.PageTransformer {
    
        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);
            }
        }
    }
    

    2.在GuideActivity中使用RotatePageTransformer。

    public class GuideActivity extends AppCompatActivity {
    
        ......
    
        /**
         * 初始化数据
         */
        private void initData() {
            images = new int[]{R.mipmap.guide_page_one, R.mipmap.guide_page_two, R.mipmap.guide_page_three, R.mipmap.guide_page_four};
            mViewPagerAdapter = new ViewPagerAdapter(GuideActivity.this, images);
            mViewPager.setAdapter(mViewPagerAdapter);
            mViewPager.setPageTransformer(false, new RotatePageTransformer());
        }
    }
    

    然后我们看下视图效果:

    gif_my_viewpager3.gif

    最后解释下RotatePageTransformer中出现的3个方法:

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

    支点是一个很神奇的属性,大家可以尝试改变它的值看下新的视图效果。

    我们的设置Y轴支点始终保持为当前View高度的一半:page.setPivotY(page.getHeight() / 2);

    现在,我们改变下Y轴支点的值,使Y轴支点始终保持为当前View的高度:page.setPivotY(page.getHeight()),运行后再来看下效果:

    gif_my_viewpager4.gif

    看来这种场景下,旋转效果没有之前的好看,但如果是水平方向的矩形图片,效果就绚丽多了...

    还有一些其他效果,简单展示一下,代码实现相对简单就不再贴源码了...

    折叠效果(前一页的滑动速度是后一页的两倍)

    gif_my_viewpage5.gif

    限于篇幅原因,ViewPager的简单使用我们就写到这了,后续小编还准备出几篇ViewPager的进阶使用,请各位敬请期待。

    相关文章

      网友评论

      本文标题:Android - ViewPager进阶篇之转场特效

      本文链接:https://www.haomeiwen.com/subject/qlsasttx.html