ViewPager2设置垂直显示导致页面内EditText焦点丢失

1,305 阅读2分钟

新开了项目,在项目中使用到了vp2,记录印象最深刻的问题。

问题描述:

页面布局为顶部titlebar,左侧是RecycleView实现的一个菜单列表,右侧通过VP2来对Fragment进行管理。

当页面内容的长度超过屏幕的3/4时,唤起软键盘会导致焦点丢失。再次点击后,输入一下后再次丢失焦点。

视频:v.qq.com/x/page/q315…

前期解决思路:

通过设置edittext,强行获取焦点。

// 当前被选中的edittext的索引
int mCheckedEditIndex ;
// 使用map来存储所有的listener,在页面释放的时候取消监听,释放资源,防止内存泄漏
// 但是leakcanary仍旧会报内存泄漏,原因待查......
protected HashMap<View, ViewTreeObserver.OnGlobalLayoutListener> mViewOnLayoutListenerHashMap;

// 设置edittext的OnTouchListener, 给mCheckedEditIndex赋值
edittext.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                mCheckedEditIndex = index;
                return false;
            }
        });

// 在给edittext设置布局变化的监听,如果当前的索引和自身的索引相同,则强制获取焦点,不是则放弃焦点
WeakReference<ItemEditBar> weakReference = new WeakReference<>(ieb);
ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                if (weakReference.get() != null) {
                    if (mCheckedEditIndex == index) {
                        weakReference.get().getEtRoot().requestFocus();
                    } else {
                        weakReference.get().getEtRoot().clearFocus();
                    }
                }
            }
        };
ieb.getEtRoot().getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);
mViewOnLayoutListenerHashMap.put(ieb, onGlobalLayoutListener);

这种思路可以解决焦点丢失的问题,但是会引入其他的问题,使用布局监听会导致内存泄漏,在较长的页面中,edittext无法取消获取焦点的动作,会导致页面滑动后 再次滑动到edittext所在位置。

再次研究后,查阅源码后发现可以设置全局的焦点变化的监听,后经过测试发现,在软键盘弹出的瞬间,焦点移动到了左侧的RecycleView的item上。结合log输出发现,此时vp2开始加载下一个页面的内容,故大胆猜测是因为vp2设置为垂直方向,在软键盘弹出时,页面重新绘制,VP2认为触发了向上的滑动操作(代码中已经设置不可滑动),VP2是使用RecycleView实现的,故滑动设置也是通过RecycleView来控制。

 private class RecyclerViewImpl extends RecyclerView {
        RecyclerViewImpl(@NonNull Context context) {
            super(context);
        }

       // ...

        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            return isUserInputEnabled() && super.onInterceptTouchEvent(ev);
        }
    }

通过测试发现,当把Vp2设置成横向模式时,便不再产生焦点丢失问题。

反思

花了一天时间,终于解决这个问题,分享给大家,请勿踩坑。

对于VP2,其核心实现方式是RecycleView,在解决这个问题的时候发现自己对RecycleView源码的理解远远不够,仍需努力,加油~~

Licy

Android开发

csdn:blog.csdn.net/li_chengyan…

掘金:juejin.cn/user/284079…

github:github.com/luckylicy