Android 有关在ListView RecycleView 中使用EditText Checkbox的坑
这是一篇文字超多的博客,哈哈哈,废话自行过滤···
-
遇到问题
在开发中我们常会在ListView , RecycleView 列表中添加EditText输入框,或者checkbox复选框。
复选框应该是用的比较多的,输入框淘宝采用的是弹出框的方式,可能在一些特定的情况下,我们希望能够直接在列表中输入,可能会更方便些。
今天说的就是两个事件
CompoundButton.OnCheckedChangeListener
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
}
});
TextChangedListener
et.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
}
});
我们可能会在Adapter中使用这两个方法来监听选择Checkbox 和 EditText 的变化。
那么我们遇到的坑是?
CheckBox
假设我们我有一个全选按钮,理想效果是:列表全部选中,全选复选框也选中,如果取消其中一个全选复选框就不选中,如果选中全选,列表全选,如果取消全选,列表取消选中。如果列表全部选中,取消其中一个,然后就会设置全选为 不选中,那么就会触发全选复选框的checkedchange事件,如果全选从选中变为 未选中,列表全部设置未选中。
说了这么多,挺复杂的,略过···
然后你以为只是列表中的复选框和全选复选框的冲突···你就错了···实际上不只如此
总之,解决复选框的问题很简单,我们不用checkedchange事件,因为这个事件不仅在用户操作是触发,其他代码中的设置也会触发。直接使用 onclick 点击事件来控制checkbox 的选中和未选,一定要把选中未选的状态加到 数据列表中。解决以Myviewholder影响的选中错乱。
EditText
这个就厉害了,我竟不知道该用什么事件来代替 TextChangedListener ,由于viewholder减少了view的加载资源耗损,也就是意味着列表中的两个不是一次加载出来的条目可能使用的是同一个viewholder。
我试过用 焦点离开来做,这个在adapter刷新时还是有一些问题。
为什么 onclick 事件不会有问题?因为 onclick一定是用户触发的,而 TextChanged、onfocus都有可能是adapter刷新获取其他原因造成你并不想触发这个这个事件,没办法区分开是用户输入的还是程序造成的。
其实本来不想写博客的,checkbox其实入坑不是第一次了,很久没开发Android,我又入坑了。主要是 EditText 的问题。好吧我看过其他解决方式是将 TextWatcher 事件像 viewholder 一样储存起来,但我也并没有解决问题。
办法肯定是有的,比如和淘宝一样弹出输入框输入,或者当用户准备输入的时候右边显示一个小图标点击一下用来保存,有点像Web上面的,能想象是什么样子吗,哈哈哈。
-
解决方法
总之我觉得就是找一个能不被其他代码影响的事件来代替 TextChanged 以及 CheckedChange 事件。 比如 onclick ,其实我觉得 EditText 在 onfocus 事件上稍加处理可能可以,因为onfocus 的影响主要是在 Adapter 刷新的时候会改变,以及用户操作时会改变。
所以,我的终极解决方案:(忽略这个丑界面)
myViewHolder.et.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean b) {
if (!b&&data.size()>position&&!myViewHolder.et.getText().toString().equals(data.get(position).getCheckValue()+"")) {
saveCheckValue(myViewHolder, position);//此方式实现将输入框数据填充到 data 数据集合中,无其他操作 即 data.get(position).setCheckValue(myViewHolder.et.getText().toString());
}
}
});
myViewHolder.et.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View view, int i, KeyEvent keyEvent) {
if (data.size()>position&&!myViewHolder.et.getText().toString().equals(data.get(position).getCheckValue()+"")) {
if (i == KeyEvent.KEYCODE_ENTER && keyEvent.getAction() == KeyEvent.ACTION_UP) {
saveCheckValue(myViewHolder, position);
}
}
return false;//返回 false 让此方法可进行其他操作,如,把光标切换到下一个输入框
}
});wujiaox
同时使用了onFocus 事件和 OnKey KEYCODE_ENTER回车事件来获取输入框中的值。
onFocus:()
①focus 有两种一种时获取焦点一种是失去焦点,我们取失去焦点。所以判断 !b
②由于操作中有新增一行,删除一行,当删除光标所在的行也会引发焦点失去的事件,此时postion的条目可能已经移出,所以判断 data.size()>position
🌂为了避免一些不必要的赋值操作,所以判断 当前data 数据集合中的值是否和当前输入框中的值是否一致,一致就不可以不必再执行赋值操作。所以判断 !myViewHolder.et.getText().toString().equals(data.get(position).getCheckValue()+"")
⭐如果在光标选中行执行删除方法,adapter刷新之后,holder 的 EditText还是会引发 focus 事件,会将删除的数据赋值给下个行的数据,难搞哦?
处理 : 在 item_layout 中加了一个EditText 在删除之前将 焦点移动到新建的 EditText 上,这样数据就会保存,在删除后就不会再引发 focus
onKey KEYCODE_ENTER
此处判断同上,用两个方法结合时为了增加用户体验,在最后一行时可以通过回车来保存,在其他行时回车能够自动定位到下一个输入框