Android RecyclerView 中多Item的EditText监听 和 EditText焦点混乱的解决方法

来源:互联网 发布:mac 网络游戏 编辑:程序博客网 时间:2024/06/04 07:48

最近在做毕业设计,使用了RecyclerView来做了以下个人资料的编辑界面。RecyclerView中包含了多种不同的Item,例如图片里面的 姓名,公司,部门,职位,邮箱的Item 里面都包含一个EditText。
这里写图片描述

RecyclerView中EditText的监听处理

这个界面的主要逻辑是监听每个EditText的输入,然后保存到个人对象里,最后保存到服务器上。RecyclerView中Item里EditText的监听可以按如下代码实现:
首先定义个回调接口:

public interface onTextChangeListener {    void onTextChanged(int pos,String str);}

在RecyclerView的自定义Adapter中添加一个如上自定义的接口成员变量mTextListener,然后在onBindViewHolder里面来添加Item中EditText的输入监听,即EditText.addTextChangedListener(),然后在监听事件回调里的afterTextChanged 方法中 调用 mTextListener.onTextChanged 来达到接口回调的目的。

public class EditListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{    private Context mContext;    private LayoutInflater mInflater;    private ArrayList<EditListBean> mList;    private onTextChangeListener mTextListener;    public EditListAdapter(Context context, ArrayList<EditListBean> list){        this.mContext=context;        mInflater=LayoutInflater.from(mContext);        this.mList=list;    }    //设置自定义接口成员变量    public void setOnTextChangeListener(onTextChangeListener onTextChangeListener){        this.mTextListener=onTextChangeListener;    }    //创建ViewHolder    @Override    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        RecyclerView.ViewHolder holder=new             itemHolder2(mInflater.inflate(R.layout.edit_recyclerview_item2,parent,false));        return holder;    }    //绑定ViewHolder    @Override    public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int    position) {     final itemHolder2 holder2= (itemHolder2) holder;    holder2.title.setText(mList.get(position).getKey());    holder2.input.setText((String) mList.get(position).getValue());    holder2.input.setHint(mList.get(position).getHint());    //添加EditText的监听事件    holder2.input.addTextChangedListener(new TextWatcher() {    @Override    public void beforeTextChanged(CharSequence s, int start, int count, int after) {    }    @Override    public void onTextChanged(CharSequence s, int start, int before, int count) {    }    @Override    public void afterTextChanged(Editable s) {    //通过接口回调将数据传递到Activity中    mTextListener.onTextChanged(position,holder2.input.getText().toString());     }     });    //内部类 ViewHolder    class itemHolder2 extends RecyclerView.ViewHolder{        TextView title;        EditText input;        public itemHolder2(View itemView) {            super(itemView);            title= (TextView) itemView.findViewById(R.id.EditActivity_item2_title);            input= (EditText) itemView.findViewById(R.id.EditActivity_item2_text);        }    }    @Override    public int getItemCount() {        return mList.size();    }    @Override    public int getItemViewType(int position){        return mList.get(position).getType();    }    }

Activity中的代码实现,在mAdapter中添加匿名内部类来监听EditText中的接口回调数据:

mAdapter.setOnTextChangeListener(new onTextChangeListener() {            @Override            public void onTextChanged(int pos, String str) {            //在这里拿到RecyclerView中Item的position和EditText中的变化                mPedit.setList(pos,str);                Log.e(String.format("%d is ---->",pos),str);            }        });

OK 上面的监听事件处理完了 我们来试试效果怎么样。首先点击姓名里面的EditText,在马化腾后面输入哈哈哈哈 然后收起键盘, 可以发现竟然下面几个Item的EditText也触发了回调事件了,也就是我编辑了Item2的EditText,然后Item7 , 9 , 11的EditText也触发了onTextChanged的监听事件了。如图,出现了监听事件错乱的重大的Bug。
这里写图片描述

Recycler中 多Item中EditText焦点混乱的解决

1 在Adapter的onBindViewHolder为每个holder.EditText设置一个Tag(可以是当前holder的positon),然后在afterTextChanged中判断holder.EditText的Tag 是否与当前holder的position是否一致来调用自定义接口,也就是使用Tag来解决视图复用带来的错乱问题,这在ListView上一般的处理方法。
在RecyclerView上效果怎么样呢? 答案是无效的,依然EditText监听错乱。这个方案PASS,不能解决。

2 正确的处理方法
在AndroidManifast.xml中设置当前Activity的标签:
添加android:windowSoftInputMode=”stateHidden|adjustPan” 属性配置

<activity android:name="view.EditActivity"            android:windowSoftInputMode="stateHidden|adjustPan"> //重点            <meta-data android:name="android.support.PARENT_ACTIVITY"                android:value="view.MyActivity"/>

来看看效果怎么样呢? 恩,很完美,现在编辑完Item2的EditText后,其他Item的EditText也不会触发监听了,那这属性配置(windowSoftInputMode)有什么作用呢??

windowSoftInputMode属性解析

android:windowSoftInputMode
Activity 的主窗口与包含屏幕软键盘的窗口的交互方式。 该属性的设置影响两个方面:
当 Activity 成为用户注意的焦点时软键盘的状态 — 隐藏还是可见。
对 Activity 主窗口所做的调整 — 是否将其尺寸调小以为软键盘腾出空间,或者当窗口部分被软键盘遮挡时是否平移其内容以使当前焦点可见

“stateHidden” 当用户选择 Activity 时 — 也就是说,当用户确实是向前导航到 Activity,而不是因离开另一 Activity 而返回时 — 隐藏软键盘。
“adjustPan” 不调整 Activity 主窗口的尺寸来为软键盘腾出空间, 而是自动平移窗口的内容,使当前焦点永远不被键盘遮盖,让用户始终都能看到其输入的内容。 这通常不如尺寸调正可取,因为用户可能需要关闭软键盘以到达被遮盖的窗口部分或与这些部分进行交互。

没有设置了adjustPan属性的效果,Activity窗口位置不变,但是尺寸变小了,也就是键盘占了Activity的下半部分,导致RecyclerView的height变小了:
这里写图片描述
设置adjustPan属性的效果,Activity窗口尺寸不变,但是位置变了,平移到上面了:
这里写图片描述

了解了这个属性后就可以对 问题的来源和解决方法 得到一个很充分的认识了,最主要还是adjustPan 这个属性。当编辑完Item2后 收起键盘后,被键盘遮挡的item会重新调用onBindViewHolder 视图复用,导致其他Item中的EditText触发监听事件。设置了android:windowSoftInputMode= adjustPan 后 会使整个Activity窗口平移,不会导致Item 被刷新,自然也不会触发监听了。

0 0
原创粉丝点击