1、場景(例如:購物車)java
一、當咱們須要以列表樣式管理某些數據時,可能須要列表項的某個字段可編輯android
二、編輯Item上的某個字段後可能還要更新相關字段的值app
2、可能遇到的問題ide
一、列表滑動致使輸入框中的數據錯位(或者焦點錯位)佈局
二、沒法更新Item上相關的字段項的值ui
三、監聽輸入框文本更改時陷入死循環this
3、可行方案(RecyclerView+TextWatcher)spa
一、用RecyclerView 實現一個ListView的效果:code
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>
二、在Adapter中自定義一個Interface 用來將輸入的值回傳給Activityblog
三、定義TxtWatcher 接收position和要同步更新的文本框
四、給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) { } } }
4、選擇RecyclerView而不是ListView的緣由
RecyclerView 在滑動的時候會使EditText失去焦點,這樣能夠觸發OnFocusChangeListener,這樣能夠更準確的綁定和解綁TxtWatcher。爲何要解綁TxtWatcher?由於在RecyclerView刷新的時候會重複觸發TextWatcher致使不少次無用的回調(甚至死循環)。
ListView在滑動的時候不會使EditText失去焦點,致使了滑動時輸入框焦點錯位,而且由於輸入框是複用的因此致使TextWatcher重複觸發不少次(多是死循環)。
5、注意在佈局中設置列表是儘可能下降RecyclerView佈局重繪的可能性(例如:固定大小等等)