RecyclerView嵌套EditView实时更新Item数据

来源:互联网 发布:linux 查看pythonpath 编辑:程序博客网 时间:2024/06/05 10:21

一、场景(例如:购物车)

1、当我们需要以列表样式管理某些数据时,可能需要列表项的某个字段可编辑

2、编辑Item上的某个字段后可能还要更新相关字段的值

二、可能遇到的问题

1、列表滑动导致输入框中的数据错位(或者焦点错位)

2、无法更新Item上相关的字段项的值

3、监听输入框文本更改时陷入死循环

三、可行方案(RecyclerView+TextWatcher

       1、用RecyclerView 实现一个ListView的效果:

package com.zhn.edit.recycler;import android.os.Bundle;import android.support.design.widget.FloatingActionButton;import android.support.design.widget.Snackbar;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.support.v7.widget.Toolbar;import android.util.Log;import android.view.View;import android.view.Menu;import android.view.MenuItem;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity implements View.OnClickListener,        EditAbleListAdapter.EditAbleListAdapterListener{    private FloatingActionButton mFLoatingBtnEmail;    private RecyclerView mRecyclerEditAble;    private LinearLayoutManager mEditAbleLayoutManager;    private EditAbleListAdapter mEditAbleListAdapter;    private List mDataGoods=new ArrayList();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mFLoatingBtnEmail = (FloatingActionButton) findViewById(R.id.floating_btn_email);        mFLoatingBtnEmail.setOnClickListener(this);        mRecyclerEditAble= (RecyclerView) findViewById(R.id.recycler_editable);        initData();    }    private void initData() {        mEditAbleLayoutManager=new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false);        mRecyclerEditAble.setLayoutManager(mEditAbleLayoutManager);        mEditAbleListAdapter=new EditAbleListAdapter(this,this);        mRecyclerEditAble.setAdapter(mEditAbleListAdapter);        for (int i=1;i<11;i++){            mDataGoods.add(new DataGoods("Goods"+i,i,i,i*i));        }        mEditAbleListAdapter.refreshDatas(mDataGoods);    }    @Override    public void onClick(View v) {        switch (v.getId()) {            case R.id.floating_btn_email:                for (int i=0;i
       2、在Adapter中自定义一个Interface 用来将输入的值回传给Activity

       3、定义TxtWatcher 接收position和要同步更新的文本框

       4、给EditText添加焦点变化的监听器,根据焦点状态绑定和解绑TxtWatcher

package com.zhn.edit.recycler;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.text.Editable;import android.text.TextWatcher;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.EditText;import android.widget.TextView;import java.util.ArrayList;import java.util.List;/** * Created by zhn * 2017/7/9 下午4:20 */public class EditAbleListAdapter extends RecyclerView.Adapter{    public void refreshDatas(List mDataGoods) {        mDatas.clear();        mDatas.addAll(mDataGoods);        notifyDataSetChanged();    }    public interface EditAbleListAdapterListener{        public void onEditTextChanged(int position,String value);    }    private Context mContext;    private List mDatas=new ArrayList();    private EditAbleListAdapterListener mListener;    public EditAbleListAdapter(Context context,EditAbleListAdapterListener listener){        this.mContext=context;        this.mListener=listener;    }    @Override    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        return new EditAbleListViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_editable_view,null));    }    @Override    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {        ((EditAbleListViewHolder)holder).setContent(position,mDatas.get(position));    }    @Override    public int getItemCount() {        return mDatas.size();    }    public class EditAbleListViewHolder extends RecyclerView.ViewHolder{        private TextView mTvItemNo;        private TextView mTvGoodsName;        private TextView mTvPrice;        private EditText mEtNum;        private TextView mTvTotalPrice;        private TxtWatcher mTxtWatcher;        public EditAbleListViewHolder(View itemView) {            super(itemView);            mTvItemNo= (TextView) itemView.findViewById(R.id.tv_item_no);            mTvGoodsName= (TextView) itemView.findViewById(R.id.tv_goods_name);            mTvPrice= (TextView) itemView.findViewById(R.id.tv_price);            mEtNum= (EditText) itemView.findViewById(R.id.et_num);            mTvTotalPrice= (TextView) itemView.findViewById(R.id.tv_total_price);            mTxtWatcher=new TxtWatcher();        }        public void setContent(int position,DataGoods data){            mTvItemNo.setText(String.valueOf(position+1));            mTvGoodsName.setText(data.getGoodsName());            mTvPrice.setText(String.valueOf(data.getPrice()));            mEtNum.setText(String.valueOf(data.getNum()));            mTvTotalPrice.setText(String.valueOf(data.getTotalPrice()));            mTxtWatcher.buildWatcher(position,mTvTotalPrice);            mEtNum.setOnFocusChangeListener(new View.OnFocusChangeListener() {                @Override                public void onFocusChange(View v, boolean hasFocus) {                    if(hasFocus){                        mEtNum.addTextChangedListener(mTxtWatcher);                    }else{                        mEtNum.removeTextChangedListener(mTxtWatcher);                    }                }            });        }    }    public class TxtWatcher implements TextWatcher{        private int mPosition;        private TextView mTvTotalPrice;        public void buildWatcher(int position,TextView view){            this.mPosition=position;            this.mTvTotalPrice=view;        }        @Override        public void beforeTextChanged(CharSequence s, int start, int count, int after) {        }        @Override        public void onTextChanged(CharSequence s, int start, int before, int count) {            if(s.length()>0){                if(mListener!=null){                    mListener.onEditTextChanged(mPosition,s.toString());                    mTvTotalPrice.setText(String.valueOf(mDatas.get(mPosition).getPrice()*Double.parseDouble(s.toString())));                }            }else{                if(mListener!=null){                    mListener.onEditTextChanged(mPosition,"0");                    mTvTotalPrice.setText("0");                }            }        }        @Override        public void afterTextChanged(Editable s) {        }    }}

四、选择RecyclerView而不是ListView的原因

        RecyclerView 在滑动的时候会使EditText失去焦点,这样可以触发OnFocusChangeListener,这样可以更准确的绑定和解绑TxtWatcher。为什么要解绑TxtWatcher?因为在RecyclerView刷新的时候会重复触发TextWatcher导致很多次无用的回调(甚至死循环)。

    ListView在滑动的时候不会使EditText失去焦点,导致了滑动时输入框焦点错位,并且因为输入框是复用的所以导致TextWatcher重复触发很多次(可能是死循环)。

五、注意在布局中设置列表是尽量降低RecyclerView布局重绘的可能性(例如:固定大小等等)




原创粉丝点击