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布局重繪的可能性(例如:固定大小等等)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM