• Android RecyclerView嵌套EditView实时更新Item数据


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

    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<datagoods> mDataGoods=new ArrayList<datagoods>();
    
        @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<mdatagoods.size();i++){ 
                log.e(mainactivity.class.getsimplename(),mdatagoods.get(i).tostring());="" }="" break;="" default:="" @override="" public="" void="" onedittextchanged(int="" position,="" string="" value)="" {="" todo="" 此处或者回调前应做值合法性验证="" mdatagoods.get(position).setnum(integer.parseint(value));="" <="" pre=""></mdatagoods.size();i++){></datagoods></datagoods>

           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<datagoods> mDataGoods) {
            mDatas.clear();
            mDatas.addAll(mDataGoods);
            notifyDataSetChanged();
        }
    
    
        public interface EditAbleListAdapterListener{
            public void onEditTextChanged(int position,String value);
        }
    
        private Context mContext;
        private List<datagoods> mDatas=new ArrayList<datagoods>();
    
        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布局重绘的可能性(例如:固定大小等等)

  • 相关阅读:
    回溯算法(DFS:深度优先)
    KNN原理和实现
    Anaconda虚拟环境控制
    c++容器
    最坏情况为线性时间的选择算法
    JVM原理解析
    substr、substring和slice的区别
    word-wrap与break-word属性的区别
    js修改伪类的值
    快速批量删除文件名中相同的文字
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/8176915.html
Copyright © 2020-2023  润新知