前言:先上一张效果图我们分析分析
由上图可知,一个功能完备的购物车至少要包括:店铺,店铺满减活动,店铺满减信息,商品,满多少免配送费,页面商品全选,同一店铺商品全选(包括反选),选中合计金额,总额,删除购物车商品,结算调起支付页面,实时修改商品数量
首先我们去实现界面,按照上图所示,可以清晰的看到稍微繁琐的就是商品列表,其他控件完全就是系统控件,这里提一点复选框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)
- 自定义View中,xml布局文件预留一个空白的LinearLayout
- 将adapter中getView方法里item的布局View传给这个自定义View;
- findById到这个LinearLayout,addView这个adapter适配器的布局View,其实这就是上述代码中initView做的工作
这样设置之后,自定义View和原本的adapter布局就连接到一起了,这时的布局在默认状态是原来的adapter条目item,侧滑删除那个小滑块是不展示的,至于说怎么侧滑才能将产品需要的侧滑做出来,这就是Touch事件来控制的效果,继续往下走: Touch事件属于Android事件分发范围