Android ViewPager2使用小计

1.解决 ViewPager2 添加 android:overScrollMode="never" 属性无效问题

  • 查阅源码得知 ViewPager2 既没有重写 setOverScrollMode() 方法也没有用到 View 的 getOverScrollMode() 方法
  • ViewPager2 会展示出 RecyclerView 的特点是因为其继承于 ViewGroup 并填充了 (protected声明的) RecyclerView 对象导致
  • ViewPage2 是 final 类

由上述分析可知,最简单的使 overScrollMode 属性生效的办法就是直接去设置 ViewPager2 中 RecyclerView 的 overScrollMode 属性,但 ViewPage2 并未暴露 RecyclerView 对象,且 ViewPager2 是 final 类无法重写。所以选择使用反射获取 RecyclerView 对象并设置 overScrollMode 属性。

    ViewPager2 mVpMain;

    private void init() {
        RecyclerView recyclerView = (RecyclerView) getPrivateValue(mVpMain, "mRecyclerView");
        if (recyclerView != null) {
            recyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
        }
    }

    /**
     * 通过反射获取私有的成员变量
     *
     * @param object
     * @return
     */
    private Object getPrivateValue(Object object, String fieldName) {

        try {
            Field field = object.getClass().getDeclaredField(fieldName);
            // 参数值为true,打开禁用访问控制检查
            //setAccessible(true) 并不是将方法的访问权限改成了public,而是取消java的权限控制检查。
            //所以即使是public方法,其accessible 属相默认也是false
            field.setAccessible(true);
            return field.get(object);
        } catch (Exception e) {
            Log.e("Test", "e.getMessage() = " + e.getMessage());
            return null;
        }
    }

 

2. ViewPager2 嵌套 RecyclerView 滑动冲突问题解决(两 View 滚动方向均为竖直滚动)

  • Android 滑动冲突解决办法常用两种:外部拦截法和内部拦截法
  • ViewPager2 是 final 类

外部拦截:父 View 根据需要对事件进行拦截,逻辑处理放在父 View 的 onInterceptTouchEvent 方法中。需要重写父 View 的 onInterceptTouchEvent 方法,并根据逻辑需要做相应的拦截

内部拦截:父 View 不拦截任何事件,所有事件都传递给子 View ,子 View 根据需要决定是自己消费事件还是给父 View 处理。子 View 需要重写 dispatchTouchEvent 方法,并根据逻辑需要通过 requestDisallowInterceptTouchEvent 方法拦截事件

因为 ViewPager2 为 final 类无法重写,所以选择内部拦截法来处理滑动冲突,重写 RecyclerView 。

/**
 * Author : Ziwen Lan
 * Date : 2019/10/30
 * Time : 13:53
 * Introduction : 处理与纵向滚动的父View的滑动冲突
 */
public class NestedRecyclerView extends RecyclerView {

    private float mStartY;

    public NestedRecyclerView(@NonNull Context context) {
        super(context);
    }

    public NestedRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public NestedRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                getParent().requestDisallowInterceptTouchEvent(true);
                mStartY = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float endY = ev.getY();
                if (endY > mStartY) {
                    //向上滑动
                    if (canScrollVertically(-1)) {
                        getParent().requestDisallowInterceptTouchEvent(true);
                    } else {
                        getParent().requestDisallowInterceptTouchEvent(false);
                    }
                } else {
                    //向下滑动
                    if ((canScrollVertically(1))) {
                        getParent().requestDisallowInterceptTouchEvent(true);
                    } else {
                        getParent().requestDisallowInterceptTouchEvent(false);
                    }
                }
                break;
            default:
                break;
        }
        return super.dispatchTouchEvent(ev);
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值