ListView中CheckBox和EditText重用问题解决方法

本人刚开始写博客,欢迎提issure;
面试时遇到直接上机实现用ListView实现同时包含EditText和CheckBox要求不允许有任何的混乱,而且得优化。面试一时没有实现,遂回来写成博客,让大家以后不要再踩此坑。

ListVeiw的Item



首先listView基本写法不讲,内部类尽量采用静态好处也不提了,直接从getView()方法开始讲起,
首先得想办法把checkBox点击状态的存起来,怎么办呢,。用map把所有的状态全存起来,然后点击的时候在checkBox的监听里把被选中的map里对应的值给改成选中状态,重新存储map
然后再从map里面把值取出来设置给checkBox;

***************以上为CheckBox的实现原理***************

通常如果listview中的item内容有edittext的时候,会出现很多问题。
主要有:
1.点击弹出编辑框,edittext会失去焦点。
2.输入内容后,向下滑动因为listview的item重用机制,你在上面输入的内容下面的item也会显示。
3.输入内容后,向下滑动再拉回来原来的数据消失。
4.在需要为edittext设置监听时会出现卡的现象
解决方法:
在EditText被点击的时候获取当前的position,在文本内容改变后把文本内容也用map存起来。然后再从map里取出来再设置给跟position对应的EditText;
原理简单:注意几个点:

1.viewHolder.editText.clearFocus();//防止点击以后弹出键盘,重新getview导致的焦点丢失
2.viewHolder.editText.requestFocus();
3.viewHolder.editText.setText(text[position]);//这一定要放在clearFocus()之后,否则最后输入的内容在拉回来时会消失

*****以上为EditText的实现原理*****

下面贴上完整代码:
MainActivity里:

    public class MainActivity extends AppCompatActivity {

    private List list;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ListView listview = (ListView) findViewById(R.id.listview);
        listview.setAdapter(new MyAdapter(MainActivity.this, getData()));
    }

    public List getData() {
        list = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            list.add(null);
        }
        return list;
    }
}

本人用的是外部适配器:
MyAdapter

/**
 * HockGod
 * 
 * Created by Administrator on 2016/11/6.
 */
public class MyAdapter extends BaseAdapter {
    private Context context;
    private List list;
    private static int index;
    private static HashMap isSelected; //存放checkBox状态的map。
    private static HashMap text;       //存放EditText输入的内容的map
    private MyWatcher myWatcher;

    public MyAdapter(Context context, List list) {
        this.context = context;
        this.list = list;
        isSelected = new HashMap();
        text = new HashMap();
        // 初始化数据
        initDate();
    }

    // 初始化isSelected的数据
    private void initDate() {
        for (int i = 0; i < list.size(); i++) {
            getIsSelected().put(i, false);
        }
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public Object getItem(int position) {
        return list.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.listview_item, null, false);
            holder = new ViewHolder(convertView);
            convertView.setTag(holder);
        } else {
            // 取出holder
            holder = (ViewHolder) convertView.getTag();
        }

        /******一下为CheckBox相关设置监听********/
        holder.cb.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if (isSelected.get(position)) {
                    isSelected.put(position, false);
                    setIsSelected(isSelected);
                } else {
                    isSelected.put(position, true);
                    setIsSelected(isSelected);
                }
                Log.e("position=========", position + "");
            }
        });
        // 根据isSelected来设置checkbox的选中状况
        holder.cb.setChecked(getIsSelected().get(position));


        /*******以下为EditText相关设置监听*********/
        holder.editText.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction()==MotionEvent.ACTION_UP){
                    index=position;
                }
                return false;
            }
        });

        //设置焦点监听,当获取到焦点的时候才给它设置内容变化监听解决卡的问题
        holder.editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {

            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                EditText editText= (EditText) v;

                if (myWatcher==null){
                    myWatcher = new MyWatcher();
                }
               if (hasFocus){
                   editText.addTextChangedListener(myWatcher);
               }else {
                   editText.removeTextChangedListener(myWatcher);
               }
            }
        });

        //防止点击以后弹出键盘,重新getview导致的焦点丢失
        holder.editText.clearFocus();

        // 如果当前的行下标和点击事件中保存的index一致,手动为EditText设置焦点。
        if (index==position) holder.editText.requestFocus();

        //这一定要放在clearFocus()之后,否则最后输入的内容在拉回来时会消失
        holder.editText.setText(text.get(position));
        holder.editText.setSelection(holder.editText.getText().length());

        return convertView;
    }

    public static HashMap getIsSelected() {
        return isSelected;
    }

    public static void setIsSelected(HashMap isSelected) {
        MyAdapter.isSelected = isSelected;
    }

    static class ViewHolder {
        CheckBox cb;
        EditText editText;

        public ViewHolder(View view){
            cb = (CheckBox) view.findViewById(R.id.cb_select);
            editText = (EditText) view.findViewById(R.id.et_text);
        }

    }

    static class MyWatcher implements 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) {

            //为输入的位置内容设置map,防止item重用机制导致的上下内容一样的问题
            text.put(index,s.toString());
        }
    }
}

如果你有更好的实现请直接贴地址。希望多多交流。不喜欢的请写出原因,本人虚心接受。

你可能感兴趣的:(android初级)