最近公司项目有这样的需求,编辑一个可动态添加删减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),虽然也算不上优雅,但至少没有自动滚动了,至于深层次的原因,恐怕要具体分析源码了
暂时先这样,后续有时间再来分析。