美文网首页自定义控件
RecycleView列表Item中包含EditText的爬坑笔

RecycleView列表Item中包含EditText的爬坑笔

作者: A挑战未来A | 来源:发表于2018-08-24 17:04 被阅读1379次

    前言:

      就我个人的开发经验而言,无论单商城还是多商城App,购物车部分编辑商品数量,都是使用“+”和“-”这种形式实现的,这种形式适用商品数量是整数型的,如果对于商品数量可能存在小数的需求,显然上述形式,没有办法满足需求,要想实现商品数量可能存在小数这样的需求,估计只能列表Item中使用EditText来实现。这样实现需求,即使我也知道,无数坑在前方向我招手,实属无奈!!!

    废话不多说,看图看需求:
    需求.png
    需求分析:
    • 列表中需要编辑数量,使用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刷新中,遇到的数据错乱问题以及控件显示问题。

    相关文章

      网友评论

        本文标题:RecycleView列表Item中包含EditText的爬坑笔

        本文链接:https://www.haomeiwen.com/subject/powbiftx.html