在ListView中動態新增EditText並對其中的資料進行儲存和由於複用引起的Editext中的內容顯示異常的解決方案
阿新 • • 發佈:2019-02-12
public class AddAdapter extends BaseAdapter { private Context context; //需要增加的條目用一個Map儲存 private Map edItem; //記錄增加的條目數,作為下標給deItem賦值,可以不要,賦值另想辦法 private int edindex = 0; private Handler handler; // 這是我繼承寫的兩個監聽,沒用匿名內部類,首先是為了方便對position這個變數進行操作,再者 // Adapter中我只分別例項化了一個監聽物件,這樣對記憶體開支應該會小些,好吧,我是對Java的垃圾回收機制信不過。 private MyFoucus myFoucus; private MyWatch myWatch; //需要儲存EditText內容的Map public HashMap inputContainer; public HashMap getInputContainer() { return inputContainer; } public AddAdapter(Context context, Handler handler) { edItem = new HashMap<>(); // 預設只加載一個Item edItem.put(edindex, "edindex"); this.context = context; this.handler = handler; inputContainer = new HashMap(); myFoucus = new MyFoucus(); myWatch = new MyWatch(); } public class ViewHolder { public EditText editText; public ViewHolder(View convertView) { editText = (EditText) convertView.findViewById(R.id.editNumber); } } @Override public int getCount() { return edItem.size(); } @Override public Object getItem(int position) { return edItem.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertView, ViewGroup viewGroup) { final ViewHolder holder; if (convertView == null) { convertView = View.inflate(context, R.layout.item_addadapterview, null); holder = new ViewHolder(convertView); // 註冊上自己寫的焦點監聽 holder.editText.setOnFocusChangeListener(myFoucus); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.editText.setTag(position); View currentFocus = ((Activity) context).getCurrentFocus(); if (currentFocus != null) { currentFocus.clearFocus(); } // 為了實現最小的記憶體開銷,複用兩個不同的監聽物件,通過每次點選的事件來修正mywatch中的position; // 使用remove和add來區別開復用修正和手動新增;之所以費勁的加個remove又加個add也是為了能儘量減少些 // 思考量,剔除修正EditText時的TextChange監聽事件,整個世界都清淨了。。。 holder.editText.removeTextChangedListener(myWatch); if (inputContainer.containsKey(position)) { holder.editText.setText(inputContainer.get(position).toString()); } else { holder.editText.setText(""); } holder.editText.addTextChangedListener(myWatch); //監聽EditText的回車鍵 holder.editText.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { if ((edItem.size() == inputContainer.size())) { edindex += 1; // 新增一項控制元件 edItem.put(edindex, "edindex"); notifyDataSetChanged(); //給Activity發訊息,讓ListView在notifyDataSetChanged之後,回到底部而不是頂部 handler.sendEmptyMessage(1); } return false; } }); return convertView; } class MyFoucus implements View.OnFocusChangeListener { // 當獲取焦點時修正myWatch中的position值,這是最重要的一步! @Override public void onFocusChange(View v, boolean hasFocus) { if (hasFocus) { int position = (int) v.getTag(); myWatch.position = position; } } } class MyWatch implements TextWatcher { // 不得不吐槽一下這裡,java的內部類機制怎麼就和我想的不一樣呢,外部依然能很輕鬆的訪問這個“私有化的”position,我是不是該去看看《think in java》了。 private int position; @Override public void afterTextChanged(Editable s) { Log.e("11111", "afterTextChanged"); //把資料儲存到Map中 inputContainer.put(position, s.toString()); } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { Log.e("11111", "beforeTextChanged"); } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { Log.e("11111", "onTextChanged"); } } } public class AddadapterActivity extends AppCompatActivity implements View.OnClickListener { private TextView textVie; private ListView listview; private AddAdapter myadapter; private Map text; private int edindex = 0; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 1: //回到底部 Log.e("11111", "case 1"); listview.setSelection(myadapter.getCount() - 1); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_addadaptermain); initView(); initData(); } private void initView() { textVie = (TextView) findViewById(R.id.textVie); listview = (ListView) findViewById(R.id.listview); textVie.setOnClickListener(this); } private void initData() { text = new HashMap<>(); text.put(edindex, "edindex"); myadapter = new AddAdapter(AddadapterActivity.this, handler); listview.setAdapter(myadapter); //對鍵盤滑動進行處理 listview.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView absListView, int scrollState) { switch (scrollState) { //當停止滾動時 case AbsListView.OnScrollListener.SCROLL_STATE_IDLE: break; //滾動時 case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL: //沒錯,下面這一坨就是隱藏軟鍵盤的程式碼 ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(AddadapterActivity.this.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); break; //手指擡起,但是螢幕還在滾動狀態 case AbsListView.OnScrollListener.SCROLL_STATE_FLING: break; } } @Override public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) { } }); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.textVie: Log.e("11111", "size = " + myadapter.getInputContainer().size()); Log.e("11111", "count = " + myadapter.getCount()); for (int i = 0; i < myadapter.getInputContainer().size(); i++) { Log.e("11111", "getInputContainer = " + myadapter.getInputContainer().get(i) + "[" + i + "]"); } for (int i = 0; i < myadapter.getCount(); i++) { Log.e("11111", "Item = " + myadapter.getItem(i) + "[" + i + "]"); } break; } } } <?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>