1. 程式人生 > >Android 仿淘寶京東等我的訂單介面及任意列表拓展

Android 仿淘寶京東等我的訂單介面及任意列表拓展

概述

目前像淘寶及展示列表等都有多個item展示的需求,可能大多數如果沒做過,第一眼就是ListView去巢狀ListView,雖然這樣是可以完成,但是這樣做會導致手機過度繪製,為什麼呢?因為當一個Item載入的時候又會去更新item裡面的adapter,apapter又會去更新自己的item,這樣就會導致載入一條x*n耗時.
淘寶訂單

解決思路

當我遇到這樣的問題時候,其實我們可以把整個List,當做一個List處理,怎麼做呢?其實就是一個複雜的ListView:
這裡寫圖片描述
- 頭部分為一個type
- 內容分為一個type
- 頂部分為一個type

然後可以通過listview或者recyclerview的getItemViewType

getViewTypeCount,特別注意一下,如果你使用了PulltoRefresh的ListView,那麼就需要getViewTypeCount返回5(3+2),為什麼呢,通過原始碼可以看到PullToRefreshListView也是add了Header.(自己可以看原始碼解決)

難點

難點其實在於對於伺服器的資料的要求.一般伺服器返回回來的資料都是一個List裡面包含了多個List:

{
    "code": "0000",
    "desc": null,
    "token": "ad762d27-ced6-4092-b415-ddad8ee0b98e__1472123395714"
, "msg": [ { "amount": 601, "consignee": "andrea", "address": "天府軟體園A區", "orderItem": [ #列表資料 { "thumbnail": null, "quantity": 1, "price": 601, "name"
: "熊貓座椅", "id": 11 } ], "freight": 0, "orderStatus": "unconfirmed", "productCount": 1, "shippingStatus": "unshipped", "phone": "15892999216", "areaName": "四川省成都市", "id": 9, "sn": "20160825202", "paymentStatus": "unpaid", "createDate": 1472123141000 }, { "amount": 601, "consignee": "andrea", "address": "天府軟體園A區", "orderItem": [ #列表資料 { "thumbnail": null, "quantity": 1, "price": 601, "name": "熊貓座椅", "id": 10 } ], "freight": 0, "orderStatus": "unconfirmed", "productCount": 1, "shippingStatus": "unshipped", "phone": "15892999216", "areaName": "四川省成都市", "id": 8, "sn": "20160825102", "paymentStatus": "unpaid", "createDate": 1472122855000 } ], "page": { "total": 8, "pageNumber": 1, "pageSize": 2 } }

遇到這樣資料,我們難道要求伺服器的哥們幫我改改嗎?如果不給改怎麼辦?當然可以解決了.怎麼辦呢?那我們就可以去拆分資料了,怎麼拆呢?:
- 把一個item拆分成三份.
- 第一份 : 保留item關係且和需要展示的頂部資料.
- 第二份 : 保留item關係且和需要展示購買列表資料.
- 第三分 : 保留item關係且和需要展示頂部購買數量,價格,支付狀態等展示或者按鈕和文字

通過上面描述,基本說明了遇到的難點.

程式碼實現

我僅僅是貼出相關的核心程式碼:

    /**
     * 拆分訂單
     *
     * @author Tanck
     * @param list
     * @return
     */
    private List<ShopOrderListResponse.MsgBean> handleList(List<ShopOrderListResponse.MsgBean> list) {
        if (null == list || 0 == list.size())
            return list;
        List<ShopOrderListResponse.MsgBean> temp = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {//拆解一個訂單
            ++total;
            bean = list.get(i);
            bean.setType(1);//給bean增加了一個type欄位,所以這樣可以用來set,為了在adapter裡面去判斷是什麼型別
            temp.add(bean);//先增加一個頭
            for (int j = 0; j < list.get(i).getOrderItem().size(); j++) {//拆解一個訂單裡面的具體每個訂單
                ++total;
                bean = (ShopOrderListResponse.MsgBean) bean.clone();//這裡用了深拷貝,是因為要對資料進行修改,後面會給出連線.

                bean.setType(2);
                bean.setOrderPosition(j);
                temp.add(bean);//增加一個內容
            }
//            ++total;
            bean = (ShopOrderListResponse.MsgBean) bean.clone();
            bean.setType(3);
            temp.add(bean);//尾部新增一個
        }
        return temp;
    }

有了拆分後,那麼就需要如何展示了.看看我的adapter吧:

    @Override
    public int getItemViewType(int position) {
        return list.get(position).getType();
    }

    @Override
    public int getViewTypeCount() {
        return 5;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {


        ViewHolder holder = null;

        if (null == convertView) {
            holder = new ViewHolder();
            switch (getItemViewType(position)) {
                case 1: // head
                    convertView = View.inflate(context, R.layout.item_shop_order_list_head, null);
                    holder.time = (TextView) convertView.findViewById(R.id.tv_item_order_time);
                    holder.status = (TextView) convertView.findViewById(R.id.tv_item_order_status);
                    holder.detailHead = (RelativeLayout) convertView.findViewById(R.id.rl_item_order_detail_head);
                    break;
                case 2:// content
                    convertView = View.inflate(context, R.layout.item_shop_order_list_content, null);
                    holder.icon = (ImageView) convertView.findViewById(R.id.iv_sp_my_order_item);
                    holder.orderMoney = (TextView) convertView.findViewById(R.id.tv_sp_my_order_money);
                    holder.number = (TextView) convertView.findViewById(R.id.tv_sp_my_order_number);
                    holder.orderName = (TextView) convertView.findViewById(R.id.tv_sp_my_order_name);
                    holder.content = (RelativeLayout) convertView.findViewById(R.id.rl_sp_my_order_content);
                    break;
                case 3: // bottom
                    convertView = View.inflate(context, R.layout.item_shop_order_list_bottom, null);
                    holder.money = (TextView) convertView.findViewById(R.id.tv_item_order_money);
                    holder.cancel = (TextView) convertView.findViewById(R.id.tv_item_order_cancel);
                    holder.pay = (TextView) convertView.findViewById(R.id.tv_item_order_pay);
                    holder.detailBottom = (LinearLayout) convertView.findViewById(R.id.ll_item_order_detail_bottom);
                    holder.opt = (RelativeLayout) convertView.findViewById(R.id.rl_item_order_opt);
                    holder.back = (TextView) convertView.findViewById(R.id.tv_item_order_back);
                    holder.backGoods = (TextView) convertView.findViewById(R.id.tv_item_order_back_goods);
                    break;
            }
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        String tempPayStatus = list.get(position).getPaymentStatus();
        String tempOrderStatus = list.get(position).getOrderStatus();
        String tempShippingStatus = list.get(position).getShippingStatus();
        holder.setListener(position);
        switch (getItemViewType(position)) {
            case 1:// head

                holder.time.setText(context.getString(R.string.order_time) + getDate(list.get(position).getCreateDate()));
                /**
                 * 訂單狀態
                 未確認
                 unconfirmed,

                 已確認
                 confirmed,

                 已完成
                 completed,

                 已取消
                 cancelled,

                 已失效
                 failure
                 */
                if ("failure".equals(tempOrderStatus)) {
                    holder.status.setText(R.string.time_out_close);
                } else if ("unpaid".equals(tempPayStatus) && "cancelled".equals(tempOrderStatus)) {
                    holder.status.setText(R.string.cancel_order);
                } else if ("unpaid".equals(tempPayStatus)) {
                    holder.status.setText(R.string.unpaid);
                } else if ("paid".equals(tempPayStatus) && "unconfirmed".equals(tempOrderStatus)) {
                    holder.status.setText(R.string.paid);
                } else if ("paid".equals(tempPayStatus) && "confirmed".equals(tempOrderStatus)) {
                    holder.status.setText(R.string.unsend);
                } else if ("shipped".equals(tempShippingStatus)) {
                    holder.status.setText(R.string.unrec);
                } else if ("received".equals(tempShippingStatus)) {
                    holder.status.setText(R.string.received);
                } else {
                    holder.status.setText(R.string.not_no);
                }
                holder.detailHead.setOnClickListener(holder);
                break;
            case 2:// content
                int tempP = list.get(position).getOrderPosition();//獲取orderItem真實位置
                String iconString = list.get(position).getOrderItem().get(tempP).getThumbnail();
                if (StringUtil.isEmpty(iconString))
                    holder.icon.setScaleType(ImageView.ScaleType.FIT_XY);
                XUtilsImageLoader.getHomeAdvImg(context, R.drawable.udesk_defualt_failure, holder.icon, iconString);
                holder.orderName.setText(list.get(position).getOrderItem().get(tempP).getName());
                holder.number.setText("x" + list.get(position).getOrderItem().get(tempP).getQuantity());
                holder.orderMoney.setText("¥" + list.get(position).getOrderItem().get(tempP).getPrice());
                holder.content.setOnClickListener(holder);
                break;
            case 3://bottom
                holder.money.setText("共" + list.get(position).getProductCount() + "件商品 實付:¥" + list.get(position).getAmount());
                holder.detailBottom.setOnClickListener(holder);
                if ("failure".equals(tempOrderStatus)) {//交易關閉
                    holder.opt.setVisibility(View.GONE);
                } else if ("unpaid".equals(tempPayStatus) && "cancelled".equals(tempOrderStatus)) {//沒給錢,點選已取消
                    holder.opt.setVisibility(View.GONE);
                } else if ("unpaid".equals(tempPayStatus)) {//待付款
                    holder.opt.setVisibility(View.VISIBLE);
                    // TODO 展示取消及付款,隱藏退貨,退款
                    holder.pay.setVisibility(View.VISIBLE);
                    holder.cancel.setVisibility(View.VISIBLE);
                    holder.back.setVisibility(View.GONE);
                    holder.backGoods.setVisibility(View.GONE);
                    holder.pay.setOnClickListener(holder);
                    holder.cancel.setOnClickListener(holder);
                } else if ("paid".equals(tempPayStatus) && "unconfirmed".equals(tempOrderStatus)) {//給了錢,沒確認
                    holder.opt.setVisibility(View.VISIBLE);
                    // TODO 展示退款,隱藏取消及付款,退貨
                    holder.cancel.setVisibility(View.GONE);
                    holder.pay.setVisibility(View.GONE);
                    holder.backGoods.setVisibility(View.GONE);
                    holder.back.setVisibility(View.VISIBLE);
                    holder.back.setOnClickListener(holder);
                } else if ("paid".equals(tempPayStatus) && "confirmed".equals(tempOrderStatus)) {//給了錢,且確認了
                    holder.opt.setVisibility(View.VISIBLE);
                    // TODO 展示退款,隱藏取消及付款,退貨
                    holder.cancel.setVisibility(View.GONE);
                    holder.pay.setVisibility(View.GONE);
                    holder.back.setVisibility(View.VISIBLE);
                    holder.backGoods.setVisibility(View.GONE);
                    holder.back.setOnClickListener(holder);
                } else if ("shipped".equals(tempShippingStatus)) {//待收貨
                    holder.opt.setVisibility(View.VISIBLE);
                    // TODO 展示退款,隱藏取消及付款,退貨(後期可能會增加檢視物流)
                    holder.cancel.setVisibility(View.GONE);
                    holder.pay.setVisibility(View.GONE);
                    holder.backGoods.setVisibility(View.GONE);
                    holder.back.setVisibility(View.VISIBLE);
                    holder.back.setOnClickListener(holder);
                } else if ("received".equals(tempShippingStatus)) {//收貨了,待評價
                    holder.opt.setVisibility(View.VISIBLE);
                    // TODO 展示退貨,隱藏取消及付款,退款
                    holder.back.setVisibility(View.GONE);
                    holder.cancel.setVisibility(View.GONE);
                    holder.pay.setVisibility(View.GONE);
                    holder.backGoods.setVisibility(View.VISIBLE);
                    holder.backGoods.setOnClickListener(holder);
                } else { // 等待確認
                    holder.opt.setVisibility(View.GONE);
                }

                break;
        }

        return convertView;
    }

總結

我們可以用一個ListView或者RecyclerView去做很多複雜型別的,為什麼這樣做不卡?因為自帶了複用機制,複用機制的話這裡就不用多說了.所以經過這樣我們就可以隨意做複雜的列表而且不卡頓.