美文网首页高级UI优秀的布局自定义控件
RecycleView结合EditText 解决变态需求---列

RecycleView结合EditText 解决变态需求---列

作者: A挑战未来A | 来源:发表于2019-02-28 11:55 被阅读225次

    前言

      我18年8月份写过一篇文章RecycleView列表Item中包含EditText的爬坑笔记,百度搜索关键词 RecycleView和EditText ,第一条结果就是这篇文章。如果小伙伴想解决日常开发中recycleView和EditText结合出现的那些坑,请移步上一篇那里。当然这篇文章同样式以上一篇文章作为基础的,建议看完上一篇文章后,再读这篇文章,能更好理解。
    [图片上传中...(image.png-9239ed-1551319103954-0)]
      好了,废话不多说,进入正题。如题目所言,日常开发中,我遇到了多次列表式信息录入的需求。大家可能不明白,列表式信息录入具体啥意思,可以看下图

    需求1.png 需求2.png

    需求1说明:

    • 养殖行业下面的细目类,条数非固定,是服务端可配置;
    • 中间是需要用户输入每条细目类对应的数量或者信息;

    需求2说明:

    • 设备信息下的设备条数是可以新增或者删除的,总之一句话,数量不固定;
    • 同样需要录入对应的信息;

    正文

      需求说明白了,看到需求的小伙伴,不知道你们有啥开发思路,反正我看到需求时候,第一反应,是想用java代码结合xml布局根据细目类数量动态添加布局的方式解决这个需求,但是细致想想,如果按照这种思路开发,逻辑复杂程度不是一般,可复用性太差,简直是自虐。再想到之前有recycleView和EditText结合的爬坑经验,最终决定继续爬坑。。。。。。
      选择继续爬坑,再细细构思开发思路,这种开发方式,我想到可能最大的问题,就是如何拿到用户录入的信息。有句伟人说过:想到的都是问题,只有做起来,才能解决问题。所以我就试着开始码代码了(开发思路其实没啥,就不总结了,就是正常使用recycleView的基本思路,不懂的小伙伴请移步recycleView)。

    • xml RecycleView文件部分(需求1和需求2在用一个页面,没毛病,外层肯定使用scrollView 进行包裹,解决滑动冲突和数据显示不全请移步杂记
    <RelativeLayout
                    android:descendantFocusability="beforeDescendants"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">
                    <android.support.v7.widget.RecyclerView
                        android:id="@+id/mRecycleHangYe"
                        android:scrollbars="none"
                        android:overScrollMode="never"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"></android.support.v7.widget.RecyclerView>
                </RelativeLayout>
    

    需要说明就是android:descendantFocusability这个属性,外层包裹RelativeLayout/LinearLayout,并添加这个属性android:descendantFocusability="blocksDescendants",是确保recycleView数量显示完全,但item中包含EditText,需要获取焦点输入内容,所以改成android:descendantFocusability="beforeDescendants"否则EditText无法获取焦点,无法输入。

    • xml Item文件部分
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:orientation="vertical"
        android:layout_height="51dp">
        <LinearLayout
            android:id="@+id/ll"
            android:background="@color/white"
            android:paddingLeft="@dimen/margin_padding_15"
            android:paddingRight="15dp"
            android:layout_width="match_parent"
            android:layout_height="@dimen/item_height">
            <TextView
    
                style="@style/applyCompanyBusinessInfo_Left"
                android:id="@+id/mTv_num"
                android:text="承保期限哈"/>
    
            <EditText
                android:inputType="number"
                android:id="@+id/mEt_num"
                android:layout_width="wrap_content"
                android:layout_height="@dimen/item_height"
                android:layout_weight="1"
                android:background="@color/white"
                android:drawablePadding="10dp"
                android:gravity="center_vertical"
                android:hint="请输入资产信息"
                android:paddingLeft="20dp"
                android:paddingRight="10dp"
                android:singleLine="true"
                android:textColor="@color/gray3"
                android:textColorHint="@color/gray9"
                android:textSize="@dimen/font_normal" />
    
            <TextView
                android:id="@+id/mTv_danwei"
                android:textColor="@color/gray3"
                android:layout_gravity="center_vertical"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text=""/>
    
        </LinearLayout>
        <View
    
            android:id="@+id/divider"
            android:layout_width="match_parent"
            android:layout_marginLeft="@dimen/padding"
            android:background="@color/gray_e3"
            android:layout_height="1dp"/>
    
    </LinearLayout>
    

    说明我开发最开始过程中,最外层部分高度*** android:layout_height="match_parent",结果运行调试发现,只显示一条数据,打印日志数据源是多条数据没问题,包裹嵌套数据显示不全不问题也处理了,只能是item部分问题,试着改成android:layout_height="51dp"***,问题解决了,细节!细节!细节哈。
    *Java recycleView部分

    mRecycleHangYe.setLayoutManager(new LinearLayoutManager(this));
    
     if (hangYeAdapter == null) {
                hangYeAdapter = new HangYeAdapter();
                mRecycleHangYe.setAdapter(hangYeAdapter);
            } else {
                hangYeAdapter.notifyDataSetChanged();
            }
    

    Java Adapter部分

    class HangYeAdapter extends RecyclerView.Adapter<HangYeAdapter.MyViewHolder> {
    
    
            @Override
            public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                View view = LayoutInflater.from(ApplyCompanyBusinessInfoActivity.this).
                        inflate(R.layout.item_apply_company_business_hangye, parent, false);
    
                return new MyViewHolder(view);
            }
    
            @Override
            public void onBindViewHolder(MyViewHolder holder, int position) {
                Logger.d("*********************onBindViewHolder");
                holder.setIsRecyclable(false);
                if (position == hangYeInfosLists.size() - 1) {
                    holder.divider.setVisibility(View.GONE);
                }
    
                HangYeInfo b = hangYeInfosLists.get(position);
                hangYeEditTextMap.put(b.getAssetName(), holder.mEtNum);
                holder.mEtNum.setInputType(TextUtils.isEmpty(b.getAssetUnit()) ?
                        InputType.TYPE_CLASS_TEXT : InputType.TYPE_CLASS_NUMBER);
                holder.mTvNum.setText(b.getAssetName());
                holder.mTvDanwei.setText(b.getAssetUnit());
                holder.mEtNum.setText(b.getNum());
    
            }
    
            @Override
            public int getItemCount() {
                return hangYeInfosLists.size();
            }
    
            class MyViewHolder extends RecyclerView.ViewHolder {
                @Bind(R.id.mTv_num)
                TextView mTvNum;
                @Bind(R.id.mEt_num)
                EditText mEtNum;
                @Bind(R.id.mTv_danwei)
                TextView mTvDanwei;
                @Bind(R.id.ll)
                LinearLayout ll;
                @Bind(R.id.divider)
                View divider;
    
                public MyViewHolder(View itemView) {
                    super(itemView);
                    ButterKnife.bind(this, itemView);
                }
            }
    
    
        }
    
    

    这里需要说明我这里拒绝了复用(数据量本身不大)holder.setIsRecyclable(false),到这里,需求1的显问题基本解决了,就剩下了,如何获取用户输入的信息这个问题了,鉴于之前的爬坑经验,我果断使用map,解决问题

    private Map<String, EditText> hangYeEditTextMap = new HashMap<>();
    

    adapter中hangYeEditTextMap.put(b.getAssetName(), holder.mEtNum),存储EditText,用的时候直接取出来:

     String key = lists.get(i).getAssetName();
                String inPutMsg = hangYeEditTextMap.get(key) != null ?
                        hangYeEditTextMap.get(key).getText().toString() : "0";
    

    重点就这一句hangYeEditTextMap.get(key).getText().toString(),其他都是逻辑问题,请忽略。这样真能获取到用户输入的数据,没有出现对应错乱的问题。Nice,需求1问题解决!!!


      到这里,小伙伴是不是觉得,需求2同样使用这种思路解决这个问题,如果有这种想法的小伙伴,你就too young, too simple, too naive需求2和需求1还是有区别的,如下:

    • 需求1列表页面,一旦数据远固定,列表item数量就固定,而列表2列表item数量是可以编辑的;
    • 需求1不涉及到刷新,需求2涉及到刷新数据;

      所以需求2还是需要单独解决的,文章RecycleView列表Item中包含EditText的爬坑笔记成功避免刷新数据,引起的无数坑,但是这里貌似不行,所以只能硬着头皮刷新。。。实现思路如下:

    • 用户初次进入,需要显示一个备用Item,供用户输入增加Item使用,所以本地创建一个对象类,包含用户录入的信息,同样也是为了记录用户输入的信息,并且在数据元增加一条空数据:
    class SheBeiBean{
            String id;
            String name;
            String num;
            String serial;
    
            public SheBeiBean(String id, String name, String num, String bianhao) {
                this.id = id;
                this.name = name;
                this.num = num;
                this.serial = bianhao;
            }
    
            public String getId() {
                return id;
            }
    
            public void setId(String id) {
                this.id = id;
            }
    
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
    
            public String getNum() {
                return num;
            }
    
            public void setNum(String num) {
                this.num = num;
            }
    
            public String getSerial() {
                return serial;
            }
    
            public void setSerial(String serial) {
                this.serial = serial;
            }
        }
    
    private ArrayList<Object> sheBeiBeansLists = new ArrayList<>();
    private void addSheBeiEmptyBean() {
            sheBeiBeansLists.add(new SheBeiBean("", "", "", ""));
        }
    
    • 之后设置recycleView布局管理器和adapter(recycleView和item的布局就不贴出来,细节注意跟需求1一样)
    private void setSheBeiAdapter() {
            if (sheBeiAdapter == null) {
                sheBeiAdapter = new SheBeiAdapter();
                mRecycleSheBei.setAdapter(sheBeiAdapter);
            } else {
                sheBeiAdapter.notifyDataSetChanged();
            }
        }
    
    

    到这里不出意外,第一个编辑部分基本显示出来了,剩下就是添加或者删除新的编辑部分,相信小伙伴们,肯定可以想到,操作数据源增加删除就可以实现,Nice,说得很对。

    class SheBeiAdapter extends RecyclerView.Adapter<SheBeiAdapter.MyViewHolder> {
    
    
            @Override
            public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                View view = LayoutInflater.from(ApplyCompanyBusinessInfoActivity.this).
                        inflate(R.layout.item_apply_company_business_shebei, parent, false);
    
                return new MyViewHolder(view);
            }
    
            @Override
            public void onBindViewHolder(MyViewHolder holder, int position) {
                holder.setIsRecyclable(false);
                holder.mTv.setVisibility(position>0?View.INVISIBLE:View.VISIBLE);
                holder.mTvDelete.setVisibility(sheBeiBeansLists.size()>1 ?View.VISIBLE:View.GONE);
                holder.mTvAdd.setVisibility(position==sheBeiBeansLists.size()-1?
                        View.VISIBLE:View.GONE);
                SheBeiBean b = (SheBeiBean) sheBeiBeansLists.get(position);
                holder.mEtName.setText(b.getName());
                holder.mEtNum.setText(b.getNum());
                holder.mEtBiaohao.setText(b.getSerial());
                holder.mEtNum.addTextChangedListener(new MyTextWatcher(MyTextWatcher.tagStr_SheBei,MyTextWatcher.TagView_num,position));
                holder.mEtName.addTextChangedListener(new MyTextWatcher(MyTextWatcher.tagStr_SheBei,MyTextWatcher.TagView_name,position));
                holder.mEtBiaohao.addTextChangedListener(new MyTextWatcher(MyTextWatcher.tagStr_SheBei,MyTextWatcher.TagView_serial,position));
                holder.mTvDelete.setTag(position);
                holder.mTvDelete.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        int index = (int) v.getTag();
                        sheBeiBeansLists.remove(index);
                        setSheBeiAdapter();
                    }
                });
                holder.mTvAdd.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        addSheBeiEmptyBean();
                        setSheBeiAdapter();
                    }
                });
    
            }
    
            @Override
            public int getItemCount() {
                return sheBeiBeansLists.size();
            }
    
            class MyViewHolder extends RecyclerView.ViewHolder {
    
                @Bind(R.id.mTv)
                TextView mTv;
                @Bind(R.id.mTvDelete)
                TextView mTvDelete;
                @Bind(R.id.mEt_name)
                EditText mEtName;
                @Bind(R.id.mEt_num)
                EditText mEtNum;
                @Bind(R.id.mEt_biaohao)
                EditText mEtBiaohao;
                @Bind(R.id.mDivider1)
                View mDivider1;
                @Bind(R.id.mTvAdd)
                TextView mTvAdd;
    
                public MyViewHolder(View itemView) {
                    super(itemView);
                    ButterKnife.bind(this, itemView);
                }
            }
    
        }
    

    到这里,就又剩下关键问题了,啥问题?当然是如何获取用户输入的信息,如果按照需求1解决的方式解决问题,明显不可能,关键问题就是需求2找不到EditText对应的独一无二的关键key,而且涉及到增加删除等问题,所以需求1解决思路基本放弃。
    问题棘手就棘手在涉及到增加删除,每次增加删除我们都是通过操作数据源(也可能是空的)实现的,另外 EditText获取输入的信息就两种方式

    • getText().ToString();
    • holder.mEtNum.addTextChangedListener();
      所以只能添加监听获取输入信息,再将信息实时的赋值到数据源中,代码如下:
     holder.mEtNum.addTextChangedListener(new MyTextWatcher(MyTextWatcher.tagStr_SheBei,MyTextWatcher.TagView_num,position));
                holder.mEtName.addTextChangedListener(new MyTextWatcher(MyTextWatcher.tagStr_SheBei,MyTextWatcher.TagView_name,position));
                holder.mEtBiaohao.addTextChangedListener(new MyTextWatcher(MyTextWatcher.tagStr_SheBei,MyTextWatcher.TagView_serial,position));
    
    
    class MyTextWatcher implements TextWatcher {
            public static final String TagView_name="name";
            public static final String TagView_num="num";
            public static final String TagView_serial="serial";
            public static final String tagStr_SheBei="shebei";
            public static final String tagStr_YuanCaiLiao="yuancailiao";
            int position;
            String viewType;
            String infoType;
            /**
             *  
             * @param infoType      区分是设备还是原材料   
             * @param viewType   区分哪editText添加的监听
             * @param position  用来获取集合中需求操作的数据源
             */
            public MyTextWatcher(String infoType,String viewType,int position) {
                this.position = position;
                this.viewType=viewType;
                this.infoType=infoType;
            }
    
            @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) {
                getUserInfoInfo(s.toString());
            }
            private void getUserInfoInfo(String inputStr){
                switch (viewType){
                    case TagView_name:
                        if(tagStr_SheBei.equals(infoType)){
                            ((SheBeiBean)sheBeiBeansLists.get(position)).setName(inputStr);
                        }else{
                            ((YuanCaiLiaoBean)yuanCaiLiaoBeanList.get(position)).setName(inputStr);
                        }
                        break;
                    case TagView_num:
                        if(tagStr_SheBei.equals(infoType)){
                            ((SheBeiBean)sheBeiBeansLists.get(position)).setNum(inputStr);
                        }else{
                            ((YuanCaiLiaoBean)yuanCaiLiaoBeanList.get(position)).setNum(inputStr);
                        }
                        break;
                    case TagView_serial:
                        ((SheBeiBean)sheBeiBeansLists.get(position)).setSerial(inputStr);
                        break;
                }
            }
        }
    

    这样,数据就实时保存到数据源中了,需要用户输入的信息的时候,直接去数据源中取可以了。到此大功告成,希望能给小伙伴一丁点启发。文章到此结束,谢谢各位看官。

    总结

    开发思路都在文章里面,想看总结的重新再看一遍文章哈。。。。。

    相关文章

      网友评论

        本文标题:RecycleView结合EditText 解决变态需求---列

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