1. 程式人生 > >Android實現電商購物車模組

Android實現電商購物車模組

前言:先上一張效果圖我們分析分析

由上圖可知,一個功能完備的購物車至少要包括:店鋪,店鋪滿減活動,店鋪滿減資訊,商品,滿多少免配送費,頁面商品全選,同一店鋪商品全選(包括反選),選中合計金額,總額,刪除購物車商品,結算調起支付頁面,實時修改商品數量

      首先我們去實現介面,按照上圖所示,可以清晰的看到稍微繁瑣的就是商品列表,其他控制元件完全就是系統控制元件,這裡提一點複選框CheckBox,CheckBox有預設的外形,當然我們一般會去自定義樣式(UI美眉要與眾不同的,必須滿足),其實很簡單隻要我們在XML佈局中給CheckBox的button屬性配置一個狀態選擇器就好,選擇器裡設定state_checked= true時讓它展示一種圖片,為false的時候展示另一個圖片就好。

   然後我們開始寫商品列表,可以看到購物車的商品列表是按照店鋪為第一層來分類的,商品是放在店鋪下邊的子類中,這種型別的資料只使用ListView(RecycleView也是一樣)是不好實現的,後來我找到一個繼承ListView的可擴充套件的控制元件ExpandableListView來實現,配合它使用的介面卡是BaseExpandableListAdapter。在做這一步的時候,產品小姐姐說我們來個側滑刪除吧,這樣使用者體驗好一點,那麼應該怎麼實現呢?

 思路是這樣滴!側滑刪除肯定是刪除商品對不對,所以我們不能滑動店鋪的時候也整出來個側滑刪除,當然一個店鋪下將其所有商品都給刪完了,那這個店鋪絕對不會還杵在那,言歸正傳,我們可以做出來一個矩形裡邊寫個刪除,在使用者手指向右到左滑動的時候,將刪除這個滑塊展示出來,點選這個滑塊,跑刪除介面重新整理UI,

  這樣就又引出來一個知識點---自定義View,先貼一段程式碼

package com.online_retailers.view.shoppingcart;

import android.content.Context;
import android.content.res.Resources;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.Scroller;
import android.widget.TextView;

import com.online_retailers.R;

public class SlideView extends LinearLayout implements View.OnClickListener {
    public static final String TAG = "SlideView";
    private static final int TAN = 2;
    private int mHolderWidth = 90;
    private float mLastX = 0;
    private float mLastY = 0;
    private LinearLayout mViewContent;
    private Scroller mScroller;
    private Context mContext;
    private Resources mResources;

    public TextView getBack() {
        return back;
    }

    private TextView back;

    public SlideView(Context context, Resources resources, View content) {
        super(context);
        initView(context, resources, content);
    }


    public SlideView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
        initView(context, context.getResources(), null);
    }

    public SlideView(Context context) {
        super(context);
        initView(context, context.getResources(), null);
    }

    private void initView(Context context, Resources resources, View content) {
        setOrientation(LinearLayout.HORIZONTAL);
        this.mContext = context;
        this.mResources = resources;
        mScroller = new Scroller(context);
        View view = LayoutInflater.from(context).inflate(resources.getLayout(R.layout.slide_view_merge), this);
        back = (TextView) view.findViewById(R.id.back);
        back.setOnClickListener(this);
        mViewContent = (LinearLayout) view.findViewById(R.id.view_content);
        mHolderWidth = getResources().getDimensionPixelSize(R.dimen.width_);
        if (content != null) {
            mViewContent.addView(content);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                float x = event.getX();
                float y = event.getY();
                float deltaX = x - mLastX;
                float deltaY = y - mLastY;
                mLastX = x;
                mLastY = y;
                if (Math.abs(deltaX) < Math.abs(deltaY) * TAN) {
                    break;
                }
                if (deltaX != 0) {
                    float newScrollX = getScrollX() - deltaX;
                    if (newScrollX < 0) {
                        newScrollX = 0;
                    } else if (newScrollX > mHolderWidth) {
                        newScrollX = mHolderWidth;
                    }
                    this.scrollTo((int) newScrollX, 0);
                }
                break;
        }
        return super.onTouchEvent(event);
    }

    private void smoothScrollTo(int destX, int destY) {
        int scrollX = getScrollX();
        int delta = destX - scrollX;
        mScroller.startScroll(scrollX, 0, delta, 0, Math.abs(delta) * 3);
        invalidate();
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            postInvalidate();
        }
    }

    /**
     * 獲取view是需要重置快取狀態
     */
    public void shrink() {
        int offset = getScrollX();
        if (offset == 0) {
            return;
        }
        scrollTo(0, 0);
    }

    public void setContentView(View view) {
        if (mViewContent != null) {
            mViewContent.addView(view);
        }
    }

    public void reset() {
        int offset = getScrollX();
        if (offset == 0) {
            return;
        }
        smoothScrollTo(0, 0);
    }

    public void adjust(boolean left) {
        int offset = getScrollX();
        if (offset == 0) {
            return;
        }
        if (offset < 20) {
            this.smoothScrollTo(0, 0);
        } else if (offset < mHolderWidth - 20) {
            if (left) {
                this.smoothScrollTo(mHolderWidth, 0);
            } else {
                this.smoothScrollTo(0, 0);
            }
        } else {
            this.smoothScrollTo(mHolderWidth, 0);
        }
    }

    @Override
    public void onClick(View v) {

    }
}

我們來分析這個自定義的矩形,首先來回顧一下,我們這個自定義矩形是要接在ExpandedList列表中具體的每個item商品佈局上的,也就是說,這個自定義View是使用在adapter介面卡上,怎麼將自定義View放到adapter介面卡的getView中,設計思路是這樣的:

 還記得怎麼給LinearLayout在程式碼中新增佈局嗎?new LinearLayout().addView(View view)

  1. 自定義View中,xml佈局檔案預留一個空白的LinearLayout
  2. 將adapter中getView方法裡item的佈局View傳給這個自定義View;
  3. findById到這個LinearLayout,addView這個adapter介面卡的佈局View,其實這就是上述程式碼中initView做的工作

  這樣設定之後,自定義View和原本的adapter佈局就連線到一起了,這時的佈局在預設狀態是原來的adapter條目item,側滑刪除那個小滑塊是不展示的,至於說怎麼側滑才能將產品需要的側滑做出來,這就是Touch事件來控制的效果,繼續往下走:

  Touch事件屬於Android事件分發範圍,如果有人不太熟悉可以看看這一篇:Android事件分發機制