Android(安卓)ViewPager2使用小计
16lz
2021-01-25
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); }}
更多相关文章
- android集成sharesdk遇到的坑无法返回app等
- Android(安卓)Audio常用音频工具和分析方法
- Android(安卓)同一个Service已经启动再多调用startService
- 解决API<8时引发的AlerDialog is not created – java.lan...
- Android按键事件——上层与驱动的映射
- (转)Android中通过Intent 调用图片、视频、音频、录音、拍照
- Android登录Web以及登录保持和cookie的使用方法
- Android(安卓)BroadCastReceiver的基本使用
- Android异步更新UI的方式之使用runOnUiThread(action)方法