美文网首页高级UI
ViewPager PageTransformer实现翻页动画

ViewPager PageTransformer实现翻页动画

作者: 爱写代码的小王子 | 来源:发表于2020-07-25 21:28 被阅读0次

环境

  • 环境:Android Studio 4.0
  • 语言:Java
  • 特点:简单,易懂,效果爆炸

分析

ViewPager是android扩展包v4包中的类,这个类可以让用户左右切换当前的view,它直接继承了ViewGroup类,所有它是一个容器类,可以在其中添加其他的view类,然后再提供一个PagerAdapter适配器类给它提供数据,再实现PageTransformer接口,Google的官方示例, 便可以得到如下效果了

效果.gif

Google的官方示例具体实现,有两种不同得实现效果

  • 第一种,深度页面变形,如上图所示效果
import android.util.Log;
import android.view.View;

import androidx.viewpager.widget.ViewPager;

public class DepthPageTransformer implements ViewPager.PageTransformer {
    private static final float MIN_SCALE = 0.75f;

    @Override
    public void transformPage(View view, float position) {
        Log.d("DepthPageTransformer", view.getTag() + " , " + 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);
        }
    }

}
  • 第二种,缩小页面变形
import android.annotation.SuppressLint;
import android.util.Log;
import android.view.View;

import androidx.viewpager.widget.ViewPager;

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)
        { // [-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);
        }
    }

}

大家如果想知道具体效果,不如在自己的电脑跑一下,看下到底有哪些变化

不过不管是那种实现,可以看出来,这里当position位于(负无穷,-1)和(1,正无穷)这两个区间的的时候,给page的透明度设为0,在[-1,1]这个区间根据一些相关极限对page进行了一些缩放和平移的操作。然后只需要在使用的时候加上这行代码

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

就能实现如上的效果了。关键就是这里计算的这些公式是怎么的出来的呢?这便是我们今天要讨论的重点了。
首先我们看一下这两个参数的解释

  public interface PageTransformer {
        /**
         * Apply a property transformation to the given page.
         * 对给定的page施加一个属性切换效果
         *
         * @param page Apply the transformation to this page
        将转换效果引用到此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.
         *                 相对于当前处于中心显示的page的postion。
         *                 0是当前页面。1是右侧页面。
         *                 -1是左侧页面。
         */
        void transformPage(View page, float position);
    }

参考网上大神的测试总结,上面大概的意思就是

  • 滑动开始前每个页面的postion是一个整数,当前页面为0,左侧页面position值为0 - 相对于当前页面偏移页面数,右侧页面postion值 0 + 相对于当前页面偏移页面数
  • 滑动结束后,每个页面的postion依然是一个整数,数值依然符合上一条规则,不过当前页面已经改变。也可以说左滑全部 -1,右滑全部 +1,postion变为0的页面成为新的当前页面
  • 每个页面的postion右滑时都在增大,左滑时都在减小,滑动后结果为滑动前结果 ±1

也就是说,不管如何滑动,当前页面和它相邻的页面的position值总是在[-1,1]之间的,所有当我们对它进行透明度、缩放、平移变化时,也需要参考这个

最后我实现了一个简单的PagerAdapter

import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import androidx.viewpager.widget.PagerAdapter;

import java.util.ArrayList;


public class ViewPagerAdapter extends PagerAdapter {


    private ArrayList<ImageView> mViewList;

    public ViewPagerAdapter(ArrayList<ImageView> mViewList) {
        this.mViewList = mViewList;
    }

    @Override
    public int getCount() {//必须实现
        return mViewList.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {//必须实现
        return view == object;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {//必须实现,实例化
        container.addView(mViewList.get(position));
        return mViewList.get(position);
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {//必须实现,销毁
        container.removeView(mViewList.get(position));
    }
}

总结:以上效果实现特别简单,但是如果想深入了解,还是需要下大力气,这是我参考的两位博主写的简书,写的特别好,简单易懂,十分感谢他们,附上原文地址
https://www.jianshu.com/p/11a819bc5973
https://www.jianshu.com/p/e5abbda4a71c

相关文章

网友评论

    本文标题:ViewPager PageTransformer实现翻页动画

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