一 引言
之前這里發布過一個RecyclerView中解決EditText各類異常的方案,存在BUG,為了方便后來人誤入這里,我把最新修復過的版本,搬到這里來了
二 效果圖(2.34 MB)
效果圖大小2.34 MB
三 解決方案
- 解析整個問題點之前,先把項目的完整demo放送給大家,地址如下:
https://github.com/kaxi4it/EditTextInRecyclerViewDemo
注:閱讀以下文章時,建議對照demo代碼對比觀看
??因為有EditText的存在,所以demo里加入了InputMethodManager來管理軟鍵盤的隱藏顯示;
??EditText的輸入內容,通過一個SparseArray來做管理,因為SparseArray比HashMap更省內存,在某些條件下性能更好,主要是因為它避免了對key的自動裝箱(int轉為Integer類型),它內部則是通過兩個數組來進行數據存儲的,一個存儲key,另外一個存儲value,為了優化性能,它內部對數據還采取了壓縮的方式來表示稀疏數組的數據,從而節約內存空間;
??EditText的焦點,我們可以通過一個int變量記錄他在adapter中的位置
//輸入法
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
//edittext里的文字內容集合
SparseArray<String> etTextAry = new SparseArray();
//edittext的焦點位置
int etFocusPos = -1;
TextWatcher textWatcher = 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) {
//每次修改文字后,保存在數據集合中
etTextAry.put(etFocusPos, s.toString());
}
};
??然后分別在onViewAttachedToWindow
(item在頁面中顯示)與onViewDetachedFromWindow
(item在頁面中隱藏)方法中,做獲取/取消焦點,添加/刪除EditText的文本變化的監聽,為何要通過這2個方法來操作,因為RecyclerView的列表緩存機制,會導致并不是每次item的顯示都會運行onBindViewHolder
方法,所以容易引起一些頁面的異常情況。
@Override
public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {
super.onViewDetachedFromWindow(holder);
ItemHolder viewHolder = (ItemHolder) holder;
//刪除文字變化監聽器
viewHolder.et.removeTextChangedListener(textWatcher);
//清除焦點
viewHolder.et.clearFocus();
//如果當前隱藏的item是焦點所在的位置,那么隱藏輸入法,否則輸入法不會自動關閉
if (etFocusPos == holder.getAdapterPosition()) {
inputMethodManager.hideSoftInputFromWindow(((ItemHolder) holder).et.getWindowToken(), 0);
}
}
@Override
public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
super.onViewAttachedToWindow(holder);
ItemHolder viewHolder = (ItemHolder) holder;
//添加文字變化監聽器
viewHolder.et.addTextChangedListener(textWatcher);
//如果當前顯示的item是焦點記錄位置,那么獲取焦點,并把光標位置置于文字最后,需要顯示輸入法的話可自行添加操作
if (etFocusPos == holder.getAdapterPosition()) {
viewHolder.et.requestFocus();
viewHolder.et.setSelection(viewHolder.et.getText().length());
}
}
??最后在onBindViewHolder
方法中,綁定數據與焦點切換時的監聽就行了
@Override
public synchronized void onBindViewHolder(RecyclerView.ViewHolder holder, int i) {
final int position = i;
ItemHolder viewHolder = (ItemHolder) holder;
viewHolder.tv.setText("item "+position);
viewHolder.et.setText(etTextAry.get(position));
viewHolder.et.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean b) {
if (b){
//記錄焦點位置
etFocusPos = position;
}
}
});
}
四 結束語
希望以上的完整DEMO和代碼的講解能幫您解決這些小問題