RecyclerView包含EditText控件导致加载数据的时候滚动到最后一个EditText焦点位置

最近公司项目有这样的需求,编辑一个可动态添加删减item的长表单,由于极端情况表单可长达30几个item,而且item还分为了几种类型,所以肯定考虑使用RecyclerView。

一开始遇到了item中含有EditText导致addTextChangedListener监听后,超出一屏导致数据混乱的问题,在网上找了几种方案,最后确定添加tag这种有效,虽然看上去代码不够优雅,还是采用了。可参考这边文章 https://www.jianshu.com/p/af820fb21e62

重点来了!!!

但是,由于我这单个item中的EditText个数多为2个及以上(因为数据是这么分类的,一个item代表一条数据,里面有三到五项数据),而且还需要缓存,在打开一个有数据缓存的

页面的时候,RecyclerView会自动滚动到底部最后一个EditText的位置。这种情况,肯定是这个EditText抢夺了焦点,导致RecyclerView滚动了。于是开始在网上找各种解决方法。

第一个找到的,直接在RecyclerView布局文件上加这两句android:focusable="true" 和 android:focusableInTouchMode="true" 如下:

<android.support.v7.widget.RecyclerView
    android:id="@+id/form_rv"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:focusable="true"
    android:focusableInTouchMode="true"
    />

或者在代码中添加:

formRv.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
formRv.setFocusable(true);
formRv.setFocusableInTouchMode(true);
formRv.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        v.requestFocusFromTouch();
        return false;
    }
});

还有说在RecyclerView外层包裹一层父View,在这个layout上添加:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:descendantFocusability="beforeDescendants"
    >
    <android.support.v7.widget.RecyclerView
        android:id="@+id/form_rv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />
</FrameLayout>

甚至在EditText的直接父布局上直接添加

android:focusable="true"

android:focusableInTouchMode="true"

或者这样:

android:descendantFocusability="blocksDescendants"      父布局里,加这句

android:overScrollMode="never"      recycleView里加这句

......

然而,以上的一切并没有什么卵用。。。RecyclerView照样自动滚动

当然scrollToPosition(0)这句代码貌似可以解决问题,但是不够优雅啊,因为自动滚动的问题还在,只不过是你调用代码又让它滚回去了,而且用户能明显感知的到。

有没有一种方法能彻底解决RecyclerView随着EditText的焦点而自动滚动的问题呢?

在百度苦苦寻觅无果之后,开始尝试去Google看看(只能翻墙,之所以一开始没Google也是墙的原因),最后在stackoverflow上发现了这篇文章https://stackoverflow.com/questions/36765265/android-edittexts-container-recyclerview-auto-scroll-when-edittext-is-focused,给了我帮助,自定义了一个LayoutManager,

public class ControlScrollLayoutManager extends LinearLayoutManager {
    private RecyclerView recyclerView;
    private boolean mCanAutoScroll;//默认不可以自动滑动,可通过setCanAutoScroll(boolean)来设置

    public ControlScrollLayoutManager(Context context, RecyclerView recyclerView) {
        this(context,VERTICAL,false,recyclerView);
    }

    public ControlScrollLayoutManager(Context context, int orientation, boolean reverseLayout, RecyclerView recyclerView) {
        super(context, orientation, reverseLayout);
        this.recyclerView = recyclerView;
    }

    public void setCanAutoScroll(boolean canAutoScroll){
        mCanAutoScroll = canAutoScroll;
    }

    @Override
    public int scrollVerticallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
        int consumedY = 0;
        // Do not let auto scroll
        if (mCanAutoScroll||recyclerView == null||recyclerView.getScrollState()!= RecyclerView.SCROLL_STATE_SETTLING){
            consumedY = super.scrollVerticallyBy(dx, recycler, state);
        }
        return consumedY;
    }
}

 

至于在什么时机控制回来可以自动滚动,看具体的逻辑吧,我是加载完数据之后再延迟设置setCanAutoScroll(true),虽然也算不上优雅,但至少没有自动滚动了,至于深层次的原因,恐怕要具体分析源码了

暂时先这样,后续有时间再来分析。

 


版权声明:本文为Kevin_s_gun原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。