1. 程式人生 > >在ListView中動態新增EditText並對其中的資料進行儲存和由於複用引起的Editext中的內容顯示異常的解決方案

在ListView中動態新增EditText並對其中的資料進行儲存和由於複用引起的Editext中的內容顯示異常的解決方案

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"?>