美文网首页RecyclerViewUI效果仿写Android学习
Android:玩转订单详情三层数据只需要一层RecyclerV

Android:玩转订单详情三层数据只需要一层RecyclerV

作者: 19snow93 | 来源:发表于2016-11-13 23:34 被阅读8578次

    大家好,我们又见面了,很高兴证明我又有东西跟大家分享了上星期我写了一篇关于[Android:玩转购物车界面和逻辑只需要一层Recyclerview,一个二层for循环和三个属性](http://www.jianshu.com/p/6c3328f87fc9),反响比我想象中好很多,而且有幸被DiyCode转发了,我自己本人也没去投稿也是有一个朋友告诉我才知道这件事~不管怎么一个阴差阳错,这也证明最近一段时间没有白做项目。

    有幸被DiyCode转发.png
    连上实习出社会工作一年多了,相比于其他办公室政治的职业,真心觉得程序猿是比较和谐的,无论是谁只要是程序猿坐在一起都可以聊大半天,互相去分享经验和学习。当然这次来不是为了跟人炫耀什么,只是想来再次分享一些更劲爆的项目经验,也是关于商城的,不过这次是购物车之后的订单列表。我们先看看界面需求: 界面需求.png
    那接下来就分析一下我自己的理解和做法。
    如果不想听我啰嗦的人可以直接去下载源码源码下载链接
    这样看上去,我们就看到有三个不同的item。
    1.一张大订单的含有所有信息的item: 一张大订单.png

    2.一张大订单里面分为一张张小订单,每张小订单就代表一间店铺的所有商品,而且每间商铺的第一个商品需要带小订单编号和商铺名字的header:


    含有商铺名和订单编号header的item.png

    3.下面的就是小订单内非第一件商品的item(不含header):


    小订单内非第一件商品.png
    看完这个界面需求,相信很多人都跟我一样,觉得用两层嵌套的RecyclerView、隐藏和显示商品的头布局不就可以完成这样的界面了?
    确实做界面的时候我是这样做的,但是当把数据插入的时候,嵌套View的问题就无缘无故出现了:
    两层RecyclerView嵌套的效果.gif

    可能gif图大家还看不出问题。


    两层RecyclerView嵌套解析图一.png
    明明是一张大订单里面有两张不同商铺的小订单,总共有五件商品,两张小订单号分别尾数是133和601,但当我们上拉RecyclerView然后再下拉回去的时候,我发现: 两层RecyclerView嵌套解析图二.png
    本来同属于一张大订单的尾数为133和601的两张小订单本来5件商品却无缘无故消失了剩下一件商品~
    得到这种结果令我非常诧异,无论我用什么样的方式去验证这样的嵌套RecyclerView的做法,都是会出现这样的情况。我的一位从我学习Android以来一直帮助我的师兄,他也去检查过我写的xml布局和adapter,也没发现问题,但显示的时候总会出现布局丢失的情况。
    最后我发现这是一条死胡同,一个我无法解释的bug。
    <u>其实在用RecyclerView嵌套的时候我已经发现很多无缘无故的显示bug,所以我劝大家还是少用布局嵌套,不然就像我这样作死~
    </u>
    既然这样走嵌套RecyclerView是一条死胡同,那只能用不嵌套的做法来做了,下面我就讲讲我的师兄,他给我的一个做法。确实在这里的做法和逻辑都是师兄写的,我只是做了实现和笔录~
    看这种做法之前,我们先看看后台返回来的数据是怎么样的,才好思考往下怎么去做: 数据结构一:大订单.png 数据结构二:大订单里面有若干个商品.png 数据结构三:每个商品信息含有该商品的商铺信息,每间商铺就是一张小订单.png

    我把以上三张图的数据结构简化一下:

    "result":{
            "大订单List":[
                大订单1{...},
                大订单2 {
                    大订单的相关信息
                    "商品List":[
                        "商品1"{
                              "商品信息"
                              "商铺信息":{
                                 商品所在商铺的信息, 即小订单信息
                            } 
                        },
                        "商品2"{...},
                        "商品3"{...},
                     ]
                },
                大订单3{...}
            ]
        }
    

    看上去,三层数据怎么把他用一层RecyclerView显示出来呢?这里,不得不说师兄想的方法非常有意思。

    他把这里的所有数据分成三种数据类型,并把RecyclerView分成三种不同的布局,对返回来的数据用不同的对象进行排序并且把排好序的数据最后放进一条List<Object>,让adapter去判断该显示哪种布局

    三种不同的对象.png

    (1)GoodsOrderInfo 表示每个小订单的头部信息(订单号、订单状态、店铺名称)

    小订单的头部信息.png

    (2)OrderGoodsItem 表示小订单中的商品

    小订单中的商品.png

    (3)OrderPayInfo 表示大订单的支付信息(金额、订单状态)

    大订单的支付信息(金额、订单状态).png

    我们来看看代码:

    public class OrderDataHelper {
        /**
         * List<Object>有三种数据类型:
         * 1、GoodsOrderInfo 表示每个小订单的头部信息(订单号、订单状态、店铺名称)
         * 2、OrderGoodsItem 表示小订单中的商品
         * 3、OrderPayInfo 表示大订单的支付信息(金额、订单状态)
         * @param resultList
         * @return
         */
        public static List<Object> getDataAfterHandle(List<OrderSummary> resultList) {
            List<Object> dataList = new ArrayList<Object>();
            //遍历每一张大订单
            for (OrderSummary orderSummary : resultList) {
                //大订单支付的金额和订单状态
                OrderPayInfo orderPayInfo = new OrderPayInfo();
                orderPayInfo.setTotalAmount(orderSummary.getTotalPrice());
                orderPayInfo.setStatus(orderSummary.getStatus());
                orderPayInfo.setId(orderSummary.getId());
                //小订单商品
                List<OrderGoodsItem> orderDetailList = orderSummary.getOrderDetailList();
                Map<String, List<OrderGoodsItem>> orderGoodsMap = new HashMap<String, List<OrderGoodsItem>>();
                Map<String, GoodsOrderInfo> orderInfoMap = new HashMap<String, GoodsOrderInfo>();
                //遍历每个大订单里面的商品
                for (OrderGoodsItem orderGoodsItem : orderDetailList) {
                    //获取商品里面的商铺信息的订单号
                    String orderCode = orderGoodsItem.getOrder().getOrderCode();
                    orderGoodsItem.setOrderid(orderSummary.getId());
                    //拿到相对应订单号的所有商品
                    List<OrderGoodsItem> goodsList = orderGoodsMap.get(orderCode);
                    //如果goodsList为空,则新建;
                    //而且把这个订单号的orderGoodsMap持有订单的对象goodsList
                    if (goodsList == null) {
                        goodsList = new ArrayList<>();
                        orderGoodsMap.put(orderCode, goodsList);
                    }
                    //goodsList添加商品的对象,因为orderGoodsMap
                    //已经持有这个订单号的goodsList对象,所以不用重新put         
                    goodsList.add(orderGoodsItem);
                    //把小订单的店铺信息赋给GoodsOrderInfo对象,并加入到orderInfoMap
                    GoodsOrderInfo orderInfo = orderInfoMap.get(orderCode);
                    if(orderInfo == null) {
                        orderInfo = new GoodsOrderInfo();
                        orderInfo.setOrderCode(orderCode);
                        orderInfo.setShopName(orderGoodsItem.getOrder().getShopName());
                        orderInfo.setStatus(orderGoodsItem.getOrder().getStatus());
                        orderInfoMap.put(orderCode, orderInfo);
                    }
                }
                //把所有数据按照头部、内容和尾部三个部分排序好
                Set<String> keySet = orderGoodsMap.keySet();
                for(String orderCode : keySet) {
                    dataList.add(orderInfoMap.get(orderCode));
                    dataList.addAll(orderGoodsMap.get(orderCode));
                }
                dataList.add(orderPayInfo);
            }
            return dataList;
        }
    }
    

    代码很简单,只是一个简单的工具类,就把后台返回来的三层数据分为了一层,一条已经排好序的List<Object>。
    然后我们就去看看简单的adapter数据显示:

    变量的声明.png

    下面就是拿到数据之后的使用:


    使用.png

    看看adapter怎么写:

    类型.png 根据不同的对象返回要显示相应布局的参数.png 根据不同的参数显示相应的ViewHolder.png 根据不同的布局做相关的处理.png 三种布局最后拼接成了理想的界面.png
    是不是很简单?其实师兄的这种做法同时也利用了RecyclerView可以显示返回不同的布局,然后通过三种不同的布局拼接来完成一层RecyclerView控制三层数据的相关做法,而且这样做并不会用到该死的嵌套RecyclerView,不会有那该死的不知道拿来的显示bug,我个人觉得真的很赞!你们觉得如何?
    感兴趣的同学可以下载源码去慢慢研究,有不同做法的同学可以提出来~
    源码下载链接

    相关文章

      网友评论

      • cryeye123:当orderDetailList 为空的时候,整个for (ContactInfo orderGoodsItem : orderDetailList) {}都没办法进入,如果orderDetailList 为null的时候是不是整个代码都需要推翻重新来写?
      • 清明捉鬼:没看完,感觉是利用多类型item同级展示,感觉实用价值不大,而且后期维护逻辑也变的复杂,如果对自定义控件没啥恐惧还是继承Recy重写下高度嵌套好点我觉得,至少逻辑上简单点,写代码最终要快乐。不知道这篇文章为什么会在首页推荐。
      • Todo2:写的非常不错,赞
        组件化和插件化的开发里程总结
        https://www.jianshu.com/p/df2a6717009d
      • 世道无情:两个listview嵌套会不会太low了:smile:
        19snow93:@世道无情 我一开始也很懵,慢慢理解就懂了,或者你有什么问题可以留言给我
        世道无情:@19snow93 上次下了你这个demo,OrderDataHelper看的不是很懂
        19snow93:@世道无情 哈,跟上潮流
      • coffeeteas:如果订单里面的产品,我想做成水平滚动该怎么做啊,嵌套Recylerview?
      • 心情是一朵云:这种实现方式是在给未来埋坑,要么解决嵌套问题,要么写自定义View。
      • 85C_bf37:如果想点击某个订单,整个订单有一个按下颜色变深的效果,这种方法没法弄吧。
      • 醉与君_aa47:大神,你好哦,我想问问这个怎么添加点击事件呢,我添加之后,只能点击订单的头部和底部,订单中间的产品界面无法点击,跪求解答
        19snow93:@醉与君_aa47 可以啊,你看看recyclerView是怎么加监听的就好
        醉与君_aa47:@19snow93 是直接在adapter里面添加点击事件吗
        19snow93:@醉与君_aa47 中间的产品也可以点吧,就是普通的position,有什么问题?
      • 五里巷:源码怎么打不开地址
        19snow93:@五里巷 可以的,老哥,再试试
      • ce99fdfc215c:帮我解决了大问题
      • thsai:今天找工作的时候机试 就是要实现这样一个界面 我作死的说两个小时可以搞定,然后想的就是这种思路 但觉得使用List<Object>这样不够优雅 然后又想不到其他方法了 然后趁着中午吃饭就溜走了,走了,了,,,,
        24d83ba5dd96:哈哈哈哈哈为什么要溜走啊哈哈哈哈哈
        19snow93:@咸鱼君 啊??
        叨叨叨_:服你哈哈哈哈哈哈哈
      • 若无初见:我举个例子:OrderGoodsItem 表示小订单中的商品没错,并且布局是一个图片一个商品名 一个数量和价钱,,那么我有这么一个需求 我要把这个小订单商品的展示变成多张图片的展示(可以理解成这个type也是一个列表) 那这个时候你要怎么做呢 这样这个type的布局不是也是recyclerview(或者addview 也是一样) 我也一直在纠结这个问题。 这样用type就做不了了吧。
      • 我叫大西瓜:楼主有没有想过里面要是有输入框和checkBox进行级联操作该怎么办呢?
      • jjkopen:之前这么干过,做全选反选的时候搞死人了.
      • cx大厦:请问,想要做 删除 某个大订单 时,要怎么处理 数据源 ,和 remove item?
      • George吴逸云:先star,然后下代码看看,嵌套确实很不合理
      • 云佾风徽:这个方式比较适合静态的订单列表页面。如果带上店铺促销信息,勾选,小计,合计这些功能的话,view type是否不便使用
        android_cyw:应该可以吧,如果勾选的是店铺头部item,则改变店铺子订单的item
      • hfk:厉害了,博主,这样也可以减少GPU过度重绘
        19snow93:@hfk 谢谢支持 :kissing_heart:
      • 薄炳鑫:不错
        19snow93: @薄炳鑫 谢谢支持😊
      • 11c708f69703:不过 它没有addfooterview 那上啦加载的时候怎么办呢?
        11c708f69703:思路较为清楚 变量名。。。。 。。。。。不忍直视 看不懂的地方是变量名 绕晕了 哈哈
        11c708f69703:谢谢 哈哈哈
        19snow93: @花花是男的 上下拉我之前写了一个,你可以回去看一下我的文章swiperecyclerview,两者完美融合
      • 11c708f69703:太酷了 我用listview嵌套listview 还有用 listview 然后中间的订单商品用new 线性布局来做 都会有重绘时的卡顿现象 先学习学习
      • 翻身不做咸鱼:吊哦,小胖
        19snow93: @LinQG 我还要多向俏少学习😊我更向往俏少的高薪工作
      • Neo_duan:写的很用心。。。我觉得你这种方式把本来一个模块的信息拆分了,不利于日后的维护,还是嵌套比较好,代码逻辑清晰。。。item高度可以动态设置固定
        前行的乌龟:@Neo_duan 嗯,我倒是觉得这种思路便于日后维护,你要是嵌套多层,你过3个月后再看肯定得话一些时间,这样写看起来思路很清晰,而且把无关的业务代码差分开,内容你要怎么加item类型随便你,店铺标题你要加item类型也随便你,都不影响其他item的视图布局和业务逻辑代码,而且位置很好找,代码修改容易,不容易造成业务混乱,很多时候都是2-3个月之后版本更新时修改,时间隔得长,谁都记不住,这样写才简单,要是整个页面的大改,那可以重新写页面了,一般也极少有这样的修改!
        Avanline:@Neo_duan recycle 没嵌套过 listview 嵌套 使用久看 会 崩溃
        19snow93: @Neo_duan 嵌套来说我自己就遇到很多奇葩的问题,所以能不用就不用,而且嵌套多了,界面也会容易卡
      • 前行的乌龟:另外github贡献了一个笑笑的星星哦 :smile:
        19snow93: @血色王冠2 谢谢
      • 前行的乌龟:嗯,很赞同楼主的话,列表嵌套层数多了的话的确是不好写逻辑,太容易出问题,调试起来也是和麻烦。楼主的思路嗯很不错,开拓了不少我的思路啊,很感谢!另外说一下,楼主的命名是否可可改改,GoodsOrderInfo,OrderGoodsItem,OrderPayInfo,这3个名字看着第一命结构不统一,第二页不利于查看,还不如叫head,body,foot ,这样看着明了,一眼看过就知道干啥的了
        19snow93: @血色王冠2 这个对象命名只是按个人喜欢的,因为要根据后台返回来的数据再做调整,并不是一成不变的,下载源码你就能看到adapter里面就是用header,content和footer来命名的

      本文标题:Android:玩转订单详情三层数据只需要一层RecyclerV

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