前言:
就我个人的开发经验而言,无论单商城还是多商城App,购物车部分编辑商品数量,都是使用“+”和“-”这种形式实现的,这种形式适用商品数量是整数型的,如果对于商品数量可能存在小数的需求,显然上述形式,没有办法满足需求,要想实现商品数量可能存在小数这样的需求,估计只能列表Item中使用EditText来实现。这样实现需求,即使我也知道,无数坑在前方向我招手,实属无奈!!!
废话不多说,看图看需求:
需求分析:
- 列表中需要编辑数量,使用RecycleView结合EditText实现;
- 输入金额不符合要求(低于起订量),刷新界面(暂时认为是刷新界面),进行提示(输入金额低于起订量)显示;
初步考虑:
- 考虑recycleView对item的复用性,item中编辑框会出现错乱,彼此相互影响的问题;
正文:
按照需求分析开发过程中,我遇到了很多坑,在这里记录几个关键的坑以及爬坑方法。
一号坑:输入框输入数量,总计联动;
解决方式:
1:在adapter中对输入框监听输入内容,通过接口将输入内容回调到activity中;
1.1:创建接口;
1.2:adapter中,构造方法中获取接口对象,onBindViewHolder方法中监听回传数据;
2:activity中创建map接收商品id和商品数量的对应关系,回调方法中根据输入内容 是否为空,添加删除指定数据;
2.1:创建map接收商品Id和商品数量对应关系
2.2:回调方法中编辑map中数据
代码按照顺序如下:
public interface ItemEditGetInfoListener {
void getUserInPutInfo(int position, String str);
}
public TiLiaoGoodsAdapter(Context context, List<TiLiaoGoodsSelectBean.DataBean.GoodsBean.GoodsListBean> list) {
this.context = context;
this.lists = list;
//activity中实现这个接口,获取接口对象
this.listener=(ItemEditGetInfoListener)context;
this.deleteListener=(ItemDeleteGetPositionListener)context;
}
TextWatcher whatch=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(final Editable editable) {
String input=editable.toString();
listener.getUserInPutInfo(position,editable.toString());
}
};
//添加监听
holder.mEtNum.addTextChangedListener(whatch);
private Map<String, Double> goodIdNumMap =new HashMap<>();
@Override
public void getUserInPutInfo(int position, String str) {
Logger.d("用户输入信息位置"+position+"输入内容"+str);
//如果用户输入内容不是空,添加数据,输入内容为空,就需要删除数据
if(!TextUtils.isEmpty(str)){
goodIdNumMap.put(uiLists.get(position).getGoodsId(),Double.valueOf(str));
}else{
goodIdNumMap.remove(uiLists.get(position).getGoodsId());
}
//对map中数据进行遍历,计算金额和总数量并展示
setGoodsInfoToButtomUi();
}
二号坑:输入数量不符合要求,进行提示
初步思路
监听输入框输入内容,当用户输入完成(1s前后输入是否一致判定是否输入完成)后,判定输入内容是否符合内容,符合不做处理,不符合,进行手动刷新,代码比较简单,就不贴出来了,思路是对的,但是实际开发过程中又引出另外几个坑。。。。。
1:刷新界面,由于复用性,输入框内容会出现错乱的问题;
解决办法
- adapter中创建map记录position和输入框num的对应关系,刷新之后,手动赋值;
- 禁用recycleView的复用性(这种方法测试的时候效果不明显):
@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
//禁用复用性
holder.setIsRecyclable(false);
setGoodsInfoToUI(holder,position);
}
2:刷新界面,会导致EditText监听错乱,反复执行,导致数据错乱;
解决办法:对EidtText使用TextWatcher做标记,添加之前先移除之前添加的监听,见代码:
private void setListener(final MyViewHolder holder, final int position, final TiLiaoGoodsSelectBean.DataBean.GoodsBean.GoodsListBean bean) {
//刷新界面的时候会触发textwatcher监听,需要提前将其移除,防止数据错乱
//参考:https://blog.csdn.net/qq953655369/article/details/72910578
//参考:https://www.jianshu.com/p/db4891bfd213
if(holder.mEtNum.getTag() instanceof TextWatcher){
holder.mEtNum.removeTextChangedListener((TextWatcher) holder.mEtNum.getTag());
}
TextWatcher whatch=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(final Editable editable) {
};
//添加监听
holder.mEtNum.addTextChangedListener(whatch);
//设置标记,为了上面删除监听使用
holder.mEtNum.setTag(whatch);
}
3:刷新界面,界面上的焦点光标消失(刷新界面,导致界面焦点改变导致的),用户体验非常不好(用户输入完成后,刷新界面,发现输入的不符合要求,想重新编辑的话,需求重新点击该编辑框,让其重新获取焦点)。
最后这个坑,按照这个思路,我真是绞尽脑汁,最终没解决。汗颜!!!需求只能开发到这里,虽然冲破重重关卡,解决无数坑,走到这里终究不完美,心有不甘啊!!!回头看看自己写的代码,有一句总结:话说当recycleView的item中有Edittext,刷新界面的时候,真是无数坑啊!最终这个大坑没解决。哎!等等,既然刷新界面这么多问题,能不能不刷新界面,实现刷新界面的效果呢?有这个想法的时候,我仿佛在绝望中看到了希望,顺着这个思路,最终还是找到了解决办法。
最终思路(最终解决办法),思路如下:
1:分别创建map对象,用于处理订单id和用户输入数量不合规需要特殊处理的控件对应关系;
private HashMap<String,View>mTvHintMap=new HashMap<>();
private HashMap<String,View>rlEditMap=new HashMap<>();
private HashMap<String,View>mEtNumMap=new HashMap<>();
@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
mTvHintMap.put(bean.getGoodsId(),holder.mTvHint);
mEtNumMap.put(bean.getGoodsId(),holder.mEtNum);
rlEditMap.put(bean.getGoodsId(),holder.rlEdit);
}
2:当用户真正输入数量不合规的时候,只需要根据id,去map中取出对应的控件,根据相应的业务逻辑对控件进行展示特殊处理(重点看整体的解决思路,业务逻辑部分没必要看);
@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
mTvHintMap.put(bean.getGoodsId(),holder.mTvHint);
mEtNumMap.put(bean.getGoodsId(),holder.mEtNum);
rlEditMap.put(bean.getGoodsId(),holder.rlEdit);
TextWatcher whatch=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(final Editable editable) {
//检查用户输入是否合法,进行相应处理
checkUserInfoIsIllegal(holder,input,minNum,position);
}
};
//添加监听
holder.mEtNum.addTextChangedListener(whatch);
}
/**获取输入值
*
*作用 检查用户输入信息是否合法
*/
private void checkUserInfoIsIllegal(final MyViewHolder holder, final String finalInput, final String finalMinNum, final int position) {
//延迟1s秒处理结果
//获取该商品Id对应的控件,方便下面进行显示隐藏
holder.rlEdit= (RelativeLayout) rlEditMap.get(lists.get(position).getGoodsId());
holder.mEtNum= (EditText) mEtNumMap.get(lists.get(position).getGoodsId());
holder.mTvHint= (TextView) mTvHintMap.get(lists.get(position).getGoodsId());
//下面是伪代码,具体实现根据具体的业务逻辑需求实现
if(满足输入条件){
holder.rlEdit,holder.mEtNum,holder.mTvHint 正常展示
}ese{
holder.rlEdit,holder.mEtNum,holder.mTvHint 非正常展示
}
//这样就避免了刷新带来的问题
}
总结
1:map中记录用户编辑数量的对应关系key使用的是goodId,最开始其实使用的是item的position,但是商品可以删除增加,使用position和编辑数量进行对应,是不安全的。最好选择不变的id或者其他不变唯一属性的作为key;
2:recycleView中禁止复用性(holder.setIsRecyclable(false);)当列表书数量不多的时候,可以考虑使用,当数量比较多的时候,不建议使用,禁用复用性,就失去了recycleView的价值;
3:这篇文章主要点:就是利用HashMap中key和value的一一对应关系,去解决RecycleView刷新中,遇到的数据错乱问题以及控件显示问题。