一看就会的 ViewPage2 的 PageTransformer 的使用!!一起冲晕他

ViewPage2 的使用相信各位大佬都信手拈来了 这里就跳过设置Adapter的步骤直接来研究他的这个PageTransformer

1 先看API

ViewPage2.setPageTransformer(@Nullable PageTransformer transformer)

less 复制代码
public void setPageTransformer(@Nullable PageTransformer transformer) 

public interface PageTransformer

less 复制代码
void transformPage(@NonNull View page, float position);

PageTransformer 接口只有一个方法 transformPage(View page, float position) 。 page就是被移动的视图,position如上解释,代表偏移量。

其中Page 在滑动过程中会被多次回调,并且每次回调的都不一定是同一个Page。因为当你在滑动中时候 你的 page0 (当前current Position)往左,而右边的page1 也会跟着一起移动,而后面的page2 也会同步移动 。其实右边的page1page2 的数量是 ,下面的这api的缓存数量来决定的

less 复制代码
public void setOffscreenPageLimit(@OffscreenPageLimit int limit)

当你的 OffscreenPageLimit = 1 ,那么默认 page1会加载。如果你的 OffscreenPageLimit2 。那么page2 会被加载,所以得看你的滑动动画ui表现。所以一般情况是不需要使用到page2的视图。所以设置 OffscreenPageLimit = 1 即可

"所以一般情况是不需要使用到page2的视图" 这里意思是,你的滑动中根本看不到page2的ui。所以不需要提前加载page2

分析OffscreenPageLimit = 1

代表缓存中会预加载加载左右两页,其实Viewpage2 内部使用RecycleView来维护的

分析transformPage

接口 PageTransformer 在滑动中回调

less 复制代码
void transformPage(@NonNull View page, float position);

而这里会被多次回调,其中如果默认冲position = 0 第一位开始的话 View page 将会是 page0page1 。意思是transformPage每次回调有可能是page0 ,也有可能是page1 ,在滑动的时候。那么如何知道滑动的距离和情况呢。现在就得观察Postion的变化。

观察Postion

问题一 pageX任意一个 , postion = 0.5是什么意思
ini 复制代码
答:说明有一个页面右滑滑到了当前Viewpage 右边的一半距离了,如图,就说明page1滑到了一半。这里前提是当前的current == 1 ,反之如果是current == 0 就是左滑
问题二 Position [0,1],[-1,0] 含义
sql 复制代码
答:其实Postion是针对可视区域(current)来说的,就是代表当前可视在屏幕中偏移量
0就是完全处于正常居中展示,1就是代表在当前的右边,-1就是在左边

设置属于自己的PageTransformer

less 复制代码
public class ViewpageActivity extends AppCompatActivity {

    @NonNull
    ActivityViewpageBinding activityViewpageBinding;


    int[] colors = {Color.BLACK, Color.DKGRAY, Color.GRAY, Color.LTGRAY, Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW, Color.CYAN, Color.MAGENTA};


    private int indexColor = 0;

    int getColorByIndex() {
        int c = colors[indexColor++];
        if (indexColor == colors.length) {
            indexColor = 0;
        }
        return c;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_viewpage);
        activityViewpageBinding = DataBindingUtil.setContentView(this, R.layout.activity_viewpage);
        activityViewpageBinding.idViewpage.setOffscreenPageLimit(1);
        activityViewpageBinding.idViewpage.setAdapter(new RecyclerView.Adapter<SimpleHodler>() {
            @NonNull
            @Override
            public SimpleHodler onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
                return new SimpleHodler(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_bg, parent, false));
            }

            @Override
            public void onBindViewHolder(@NonNull SimpleHodler holder, int position) {
                holder.contentView.setBackgroundColor(getColorByIndex());
            }

            @Override
            public int getItemCount() {
                return Integer.MAX_VALUE;
            }
        });
        activityViewpageBinding.idViewpage.setCurrentItem(Integer.MAX_VALUE / 2);


        activityViewpageBinding.idViewpage.addItemDecoration(new RecyclerView.ItemDecoration() {
            @Override
            public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
                outRect.right = 100;
                outRect.left = 100;
            }
        });
        activityViewpageBinding.idViewpage.setPageTransformer(new ViewPager2.PageTransformer() {
            @Override
            public void transformPage(@NonNull View page, float position) {
                page.setTranslationX(-150 * position);
            }
        });
    }


    static class SimpleHodler extends RecyclerView.ViewHolder {
        View contentView;

        public SimpleHodler(@NonNull View itemView) {
            super(itemView);
            contentView = itemView.findViewById(R.id.id_view);
        }
    }

}

page.setTranslationX(-150 * position); 核心代码,就是让左右两边挤过来。

可以这样尝试理解;

当你左边不滑动时候,这个左page TranslationX = -150 * -1 = 150 ;向迁移150个像素

当你右边不滑动时候,这个右page TranslationX = -150 * 1 = -150 ;向迁移150个像素

再配合 ItemDecoration outRect.right = 100; outRect.left = 100; 给每个page增加左右100像素间距

这是就是简单的卡片效果

如果你想加其他效果比如放大/缩小

less 复制代码
activityViewpageBinding.idViewpage.setPageTransformer(new ViewPager2.PageTransformer() {
    @Override
    public void transformPage(@NonNull View page, float position) {
        page.setTranslationX(-350 * position);
        page.setScaleX(1 - Math.abs(position) * 0.4f);
        page.setScaleY(1 - Math.abs(position) * 0.4f);
    }
});

其他效果比如透明度和旋转

less 复制代码
activityViewpageBinding.idViewpage.setPageTransformer(new ViewPager2.PageTransformer() {
    @Override
    public void transformPage(@NonNull View page, float position) {
        page.setTranslationX(-350 * position);
        page.setScaleX(1 - Math.abs(position) * 0.4f);
        page.setScaleY(1 - Math.abs(position) * 0.4f);

        page.setAlpha(1 - Math.abs(position) * 0.7f);
        page.setRotation(10 * position);
        
    }
});

总结

只要使用中把握住 -1,0,1的变量即可。比如 你需要一个透明渐变 在左右两边是 0.5f alpha,那么你可以先写好,最基本的3个固定值用来观测

左边, position = -1 写成 setAlpha(--1 * 0.5)

中间, position = 0 任意 setAlpha(0 * 0.5)

右边边,position = 1 写成 setAlpha(1 * 0.5)

所以但你要综合情况的时候得出 page.setAlpha(1 - Math.abs(position) * 0.7f); 这公式既满足了 position = -1 也满足 position = 1 也满足 position = 0 。这个代码就是最终的表现方式

其他的也一样道理,如果情况很复杂还可以分别判断

scss 复制代码
if(position >= 0 ){
    ****
}else if(postion <0){
    ****
}

好了希望能帮到有需要的人

相关推荐
明月清风徐徐18 分钟前
Vue实训---2-路由搭建
前端·javascript·vue.js
王解26 分钟前
速度革命:esbuild如何改变前端构建游戏 (1)
前端·vite·esbuild
葡萄城技术团队34 分钟前
使用 前端技术 创建 QR 码生成器 API1
前端
DN金猿36 分钟前
Vue移动端网页(H5)预览pdf文件(pdfh5和vue-pdf)(很详细)
前端·vue.js·pdf
鸽鸽程序猿44 分钟前
【前端】javaScript
开发语言·前端·javascript
秦时明月之君临天下1 小时前
React和Next.js的相关内容
前端·javascript·react.js
上官花雨1 小时前
什么是axios?怎么使用axios封装Ajax?
前端·ajax·okhttp
米奇妙妙wuu1 小时前
React中 setState 是同步的还是异步的?调和阶段 setState 干了什么?
前端·javascript·react.js
李刚大人1 小时前
react-amap海量点优化
前端·react.js·前端框架
闹闹没有闹2 小时前
socket连接封装
前端