android 仿美团购物车,Android 美团购物车效果

老规矩先上效果图

e4e0c8302563

美团购物车.gif

2020-11-23新增吸顶和Fragment配合

e4e0c8302563

gif (2).gif

GIF图有点不清楚,再上两张截图

e4e0c8302563

Wec1111.jpeg

e4e0c8302563

Wech222.jpeg

效果就是gif展示的,效果图有了,还是要用文字介绍下的。

效果就是左右两个列表,左侧列表点击时,右侧的标题自动显示到列表的顶部,标题是悬浮吸顶的,没组的标题固定悬浮在顶部,当右侧列表滑动时,左侧列表自动定位至和左侧相同的分类保持统一,底部的弹出购物车区域,购物车的高度是在屏幕的70%以下是自适应的高度,最大高度是当前屏幕的70%,下边是部分代码和实现思路。

这个效果主要要处理的就是两个RecyclerView 的互相交互和数据处理

e4e0c8302563

image.png

这就是整个页面的主要布局,两个recyclerView

至于右侧又一个热销水果的标题,其实使用StickyHeaderLayoutManager 也可以使用标题吸顶,但是使用这个类的话,在后边左侧点击让右侧显示到顶部的时候会特别难处理,而且StickyHeaderLayoutManager这个Manager里边也没有recyclerView的.scrollToPositionWithOffset()方法。

这个方法主要就是为了让这个东西在顶部

e4e0c8302563

image.png

这里提到了scrollToPositionWithOffset()方法,就顺便说一下scrollToPosition和scrollToPositionWithOffset的区别

scrollToPosition 会把不在屏幕的 Item 移动到屏幕上,原来在上方的 Item 移动到 可见 Item 的第一项,在下方的移动到屏幕可见 Item 的最后一项。已经显示的 Item 不会移动。

scrollToPositionWithOffset 会把 Item 移动到可见 Item 的第一项,即使它已经在可见 Item 之中。另外它还有 offset 参数,表示 Item 移动到第一项后跟 RecyclerView 上边界或下边界之间的距离(默认是 0)

要实现这个效果还就得使用scrollToPositionWithOffset()这个方法,我也没有重写一个Manager,就这样直接使用了

使用到的数据结构

e4e0c8302563

image.png

就是一个简单的省市结构类型

这里我也把JSON放上来了

[{"productEntities":[{"parentId":"1","productCartMoney":0.0,"productCount":0,"productId":"1","productImg":"img地址","productMoney":10.0,"productMonth":"34","productName":"新上市猕猴桃1-1"},{"parentId":"1","productCartMoney":0.0,"productCount":0,"productId":"2","productImg":"img地址","productMoney":20.0,"productMonth":"34","productName":"新上市猕猴桃2-1"},{"parentId":"1","productCartMoney":0.0,"productCount":0,"productId":"3","productImg":"img地址","productMoney":30.0,"productMonth":"34","productName":"新上市猕猴桃3-1"},{"parentId":"1","productCartMoney":0.0,"productCount":0,"productId":"4","productImg":"img地址","productMoney":40.0,"productMonth":"34","productName":"新上市猕猴桃4-1"},{"parentId":"1","productCartMoney":0.0,"productCount":0,"productId":"5","productImg":"img地址","productMoney":50.0,"productMonth":"34","productName":"新上市猕猴桃5-1"},{"parentId":"1","productCartMoney":0.0,"productCount":0,"productId":"6","productImg":"img地址","productMoney":50.0,"productMonth":"34","productName":"新上市猕猴桃6-1"},{"parentId":"1","productCartMoney":0.0,"productCount":0,"productId":"7","productImg":"img地址","productMoney":50.0,"productMonth":"34","productName":"新上市猕猴桃7-1"}],"typeCount":0,"typeId":"1","typeName":"热销水果"}]

数据源准备完之后就开始下面的实现了

设置adapter

//设置数据源,数据绑定展示

leftAdapter = new LeftProductTypeAdapter(MainActivity.this, productListEntities);

rightAdapter = new RightProductAdapter(MainActivity.this, productListEntities, shopCart);

rightMenu.setAdapter(rightAdapter);

leftMenu.setAdapter(leftAdapter);

//左侧列表单项选择

leftAdapter.addItemSelectedListener(this);

rightAdapter.setShopCartImp(this);

//设置初始头部

initHeadView();

刚才从图上也看到了右侧列表又一个标题,这个标题就是为了占位和显示使用

/**

* 初始头部

*/

private void initHeadView() {

headMenu = rightAdapter.getMenuOfMenuByPosition(0);

headerLayout.setContentDescription("0");

headerView.setText(headMenu.getTypeName());

}

别忘了设置LayoutManager,这里为什么使用LinearLayoutManager在上边也说了,主要是使用LinearLayoutManager的scrollToPositionWithOffset()方法

leftMenu.setLayoutManager(new LinearLayoutManager(this));

rightMenu.setLayoutManager(new LinearLayoutManager(this));

数据绑定之后,就是列表的滑动了,先说右侧列表数据滑动,然后让左侧选中

右侧列表滑动监听

rightMenu.addOnScrollListener(new RecyclerView.OnScrollListener() {

@Override

public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {

super.onScrollStateChanged(recyclerView, newState);

}

@Override

public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {

super.onScrolled(recyclerView, dx, dy);

if (recyclerView.canScrollVertically(1) == false) {//无法下滑

showHeadView();

return;

}

View underView = null;

if (dy > 0) {

underView = rightMenu.findChildViewUnder(headerLayout.getX(), headerLayout.getMeasuredHeight() + 1);

} else {

underView = rightMenu.findChildViewUnder(headerLayout.getX(), 0);

}

if (underView != null && underView.getContentDescription() != null) {

int position = Integer.parseInt(underView.getContentDescription().toString());

ProductListEntity menu = rightAdapter.getMenuOfMenuByPosition(position);

if (leftClickType || !menu.getTypeName().equals(headMenu.getTypeName())) {

if (dy > 0 && headerLayout.getTranslationY() <= 1 && headerLayout.getTranslationY() >= -1 * headerLayout.getMeasuredHeight() * 4 / 5 && !leftClickType) {// underView.getTop()>9

int dealtY = underView.getTop() - headerLayout.getMeasuredHeight();

headerLayout.setTranslationY(dealtY);

} else if (dy < 0 && headerLayout.getTranslationY() <= 0 && !leftClickType) {

headerView.setText(menu.getTypeName());

int dealtY = underView.getBottom() - headerLayout.getMeasuredHeight();

headerLayout.setTranslationY(dealtY);

} else {

headerLayout.setTranslationY(0);

headMenu = menu;

headerView.setText(headMenu.getTypeName());

for (int i = 0; i < productListEntities.size(); i++) {

if (productListEntities.get(i) == headMenu) {

leftAdapter.setSelectedNum(i);

break;

}

}

if (leftClickType) leftClickType = false;

}

}

}

}

});

private void showHeadView() {

headerLayout.setTranslationY(0);

View underView = rightMenu.findChildViewUnder(headerLayout.getX(), 0);

if (underView != null && underView.getContentDescription() != null) {

int position = Integer.parseInt(underView.getContentDescription().toString());

ProductListEntity entity = rightAdapter.getMenuOfMenuByPosition(position + 1);

headMenu = entity;

headerView.setText(headMenu.getTypeName());

for (int i = 0; i < productListEntities.size(); i++) {

if (productListEntities.get(i) == headMenu) {

leftAdapter.setSelectedNum(i);

break;

}

}

}

}

以上代码就是两个列表滑动交互右侧的主要代码,以上实现的是右侧滑动分组置顶的效果

接下来就是

右侧滑动,左侧选中

选中的主要代码是LeftProductTypeAdapter中的setSelectedNum();

/**

* 选中左侧区域

*

* @param selectedNum

*/

public void setSelectedNum(int selectedNum) {

if (selectedNum < getItemCount() && selectedNum >= 0) {

this.mSelectedNum = selectedNum;

notifyDataSetChanged();

}

}

然后adapter中设置选中的样式就可以

@Override

public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

ProductListEntity dishMenu = mMenuList.get(position);

LeftMenuViewHolder viewHolder = (LeftMenuViewHolder) holder;

viewHolder.menuName.setText(dishMenu.getTypeName());

if (mSelectedNum == position) {

viewHolder.menuLayout.setSelected(true);

} else {

viewHolder.menuLayout.setSelected(false);

}

说完了右侧滑动让左侧选中,那么接下来就是左侧点击让右侧对应的分组显示出来

左侧列表点击,右侧分组显示在顶部

在LeftProductTypeAdapter中暴露接口

public interface onItemSelectedListener {

public void onLeftItemSelected(int postion, ProductListEntity menu);

}

public void addItemSelectedListener(onItemSelectedListener listener) {

if (mSelectedListenerList != null)

mSelectedListenerList.add(listener);

}

在Activity中实现,这里直接使用scrollToPositionWithOffset方法就可以了,相对来说比较简单

/**

* 左侧列表单项选中

*

* @param position

* @param menu

*/

@Override

public void onLeftItemSelected(int position, ProductListEntity menu) {

int sum = 0;

for (int i = 0; i < position; i++) {

sum += productListEntities.get(i).getProductEntities().size() + 1;

}

// StickyHeaderLayoutManager layoutManager = (StickyHeaderLayoutManager) rightMenu.getLayoutManager();

LinearLayoutManager layoutManager = (LinearLayoutManager) rightMenu.getLayoutManager();

rightMenu.scrollToPosition(position);

layoutManager.scrollToPositionWithOffset(sum, 0);

leftClickType = true;

}

目前为至,左右两个列表就可以实现交互了,左侧点击右侧显示指定数据,右侧滑动左侧选中对应的内容

列表的联动处理完成,接下来就是右侧列表商品加减操作了

右侧列表加减处理

右侧列表的加减操作这里没有暴露到Activity中操作,是在Adapter中设置的

RightProductAdapter

//加减点击时间

dishholder.iv_group_list_item_count_add.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View view) {

Log.e("posss", "-------------------posss:" + posss);

if (shopCart.addShoppingSingle(dish)) {

// notifyItemChanged(position);

//当前数字变化刷新

notifyDataSetChanged();

if (shopCartImp != null) {

shopCartImp.add(view, position,dish);

}

}

}

});

dishholder.iv_group_list_item_count_reduce.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View view) {

if (shopCart.subShoppingSingle(dish)) {

// notifyItemChanged(position);

//当前数字变化刷新

notifyDataSetChanged();

if (shopCartImp != null)

shopCartImp.remove(view, position,dish);

}

}

});

这里没有使用notifyItemChanged()方法刷新,因为这个方法,完成操作之后刷新,商品图片有闪烁效果,所以这里使用的notifyDataSetChanged()方法替代

在上边adapter中的处理中,我们看到了shopCart.addShoppingSingle(dish) 的判读

这里的shopCart 是一个购物车实体,可以理解为 中转处

看下ShopCart的内容

public class ShopCart {

private int shoppingAccount;//数量

private double shoppingTotalPrice;//购物车总价格

private Map shoppingSingle;//保存数量

private Map parentCountMap;//父保存数量

public ShopCart() {

this.shoppingAccount = 0;

this.shoppingTotalPrice = 0.0;

this.shoppingSingle = new HashMap<>();

this.parentCountMap = new HashMap<>();

}

public boolean addShoppingSingle(ProductListEntity.ProductEntity dish) {

double remain = dish.getProductCartMoney();

// if (remain <= 0)

// return false;

//商品的价格,减操作直接--

dish.setProductCartMoney(--remain);

int num = 0;

if (shoppingSingle.containsKey(dish)) {

num = shoppingSingle.get(dish);

}

num += 1;

/***/

dish.setProductCount(num);

shoppingSingle.put(dish, num);

//如果这个map存在这个父ID的值

int parentNum = 0;

if (parentCountMap.containsKey(dish.getParentId())) {

parentNum = parentCountMap.get(dish.getParentId());

parentNum += 1;

} else {//如果第一次存储

parentNum = 1;

}

parentCountMap.put(dish.getParentId(), parentNum);

Log.e("TAG", "addShoppingSingle: " + shoppingSingle.get(dish));

shoppingTotalPrice += dish.getProductMoney();//加商品的正常价格

shoppingAccount += num;

return true;

}

public boolean subShoppingSingle(ProductListEntity.ProductEntity dish) {

int num = 0;

if (shoppingSingle.containsKey(dish)) {

num = shoppingSingle.get(dish);

}

if (num <= 0) return false;

num--;

double remain = dish.getProductCartMoney();

dish.setProductCartMoney(++remain);

dish.setProductCount(num);

shoppingSingle.put(dish, num);

if (num == 0) {

shoppingSingle.remove(dish);

}

//如果这个map存在这个父ID的值

int parentNum = 0;

if (parentCountMap.containsKey(dish.getParentId())) {

parentNum = parentCountMap.get(dish.getParentId());

parentNum -= 1;

parentCountMap.put(dish.getParentId(), parentNum);

}

shoppingTotalPrice -= dish.getProductMoney();

shoppingAccount -= num;

return true;

}

public int getShoppingAccount() {

return shoppingSingle.size();

}

public void setShoppingAccount(int shoppingAccount) {

this.shoppingAccount = shoppingAccount;

}

public double getShoppingTotalPrice() {

return shoppingTotalPrice;

}

public void setShoppingTotalPrice(double shoppingTotalPrice) {

this.shoppingTotalPrice = shoppingTotalPrice;

}

public Map getShoppingSingle() {

return shoppingSingle;

}

public void setShoppingSingle(Map shoppingSingle) {

this.shoppingSingle = shoppingSingle;

}

public Map getParentCountMap() {

return parentCountMap;

}

public void setParentCountMap(Map parentCountMap) {

this.parentCountMap = parentCountMap;

}

public void clear() {

this.shoppingAccount = 0;

this.shoppingTotalPrice = 0;

this.shoppingSingle.clear();

}

说了点击在adapter中实现,但是还有加入动画,所以还是暴露接口给Activity使用

ShopCartImp

public interface ShopCartImp {

void add(View view, int postion, ProductListEntity.ProductEntity entity);

void remove(View view, int postion, ProductListEntity.ProductEntity entity);

}

右侧列表加+

由于只有在加的时候才有动画效果,只有只给add设置addCart动画效果,加只需要注意是不是第一次添加就可以,如果是第一次添加,ShopCart中已经判断了,第一次直接put,否则就只改变count就可以了

/**

* 购物车+

*

* @param view

* @param position

*/

@Override

public void add(View view, int position, ProductListEntity.ProductEntity entity) {

addCart(view, entity);

}

加入购物车动画方法

//加入购物车曲线动画

private void addCart(View view, ProductListEntity.ProductEntity entity) {

// 一、创造出执行动画的主题---imageview

//代码new一个imageview,图片资源是上面的imageview的图片

// (这个图片就是执行动画的图片,从开始位置出发,经过一个抛物线(贝塞尔曲线),移动到购物车里)

final ImageView goods = new ImageView(MainActivity.this);

goods.setImageDrawable(getResources().getDrawable(R.drawable.shape_shopping_cart_num_bg, null));

RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(50, 50);

rl.addView(goods, params);

// 二、计算动画开始/结束点的坐标的准备工作

//得到父布局的起始点坐标(用于辅助计算动画开始/结束时的点的坐标)

int[] parentLocation = new int[2];

rl.getLocationInWindow(parentLocation);

//得到商品图片的坐标(用于计算动画开始的坐标)

int startLoc[] = new int[2];

view.getLocationInWindow(startLoc);

//得到购物车图片的坐标(用于计算动画结束后的坐标)

int endLoc[] = new int[2];

iv_shopping_cart_img.getLocationInWindow(endLoc);

// 三、正式开始计算动画开始/结束的坐标

//开始掉落的商品的起始点:商品起始点-父布局起始点+该商品图片的一半

float startX = startLoc[0] - parentLocation[0] + goods.getWidth() / 2;

float startY = startLoc[1] - parentLocation[1] + goods.getHeight() / 2;

//商品掉落后的终点坐标:购物车起始点-父布局起始点+购物车图片的1/5

float toX = endLoc[0] - parentLocation[0] + iv_shopping_cart_img.getWidth() / 5;

float toY = endLoc[1] - parentLocation[1];

// 四、计算中间动画的插值坐标(贝塞尔曲线)(其实就是用贝塞尔曲线来完成起终点的过程)

//开始绘制贝塞尔曲线

Path path = new Path();

//移动到起始点(贝塞尔曲线的起点)

path.moveTo(startX, startY);

//使用二次萨贝尔曲线:注意第一个起始坐标越大,贝塞尔曲线的横向距离就会越大,一般按照下面的式子取即可

path.quadTo((startX + toX) / 2, startY, toX, toY);

//mPathMeasure用来计算贝塞尔曲线的曲线长度和贝塞尔曲线中间插值的坐标,

// 如果是true,path会形成一个闭环

mPathMeasure = new PathMeasure(path, false);

//★★★属性动画实现(从0到贝塞尔曲线的长度之间进行插值计算,获取中间过程的距离值)

ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, mPathMeasure.getLength());

valueAnimator.setDuration(500);

// 匀速线性插值器

valueAnimator.setInterpolator(new LinearInterpolator());

valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

// 当插值计算进行时,获取中间的每个值,

// 这里这个值是中间过程中的曲线长度(下面根据这个值来得出中间点的坐标值)

float value = (Float) animation.getAnimatedValue();

// ★★★★★获取当前点坐标封装到mCurrentPosition

// boolean getPosTan(float distance, float[] pos, float[] tan) :

// 传入一个距离distance(0<=distance<=getLength()),然后会计算当前距

// 离的坐标点和切线,pos会自动填充上坐标,这个方法很重要。

mPathMeasure.getPosTan(value, mCurrentPosition, null);//mCurrentPosition此时就是中间距离点的坐标值

// 移动的商品图片(动画图片)的坐标设置为该中间点的坐标

goods.setTranslationX(mCurrentPosition[0]);

goods.setTranslationY(mCurrentPosition[1]);

}

});

// 五、 开始执行动画

valueAnimator.start();

// 六、动画结束后的处理

valueAnimator.addListener(new Animator.AnimatorListener() {

@Override

public void onAnimationStart(Animator animation) {

}

//当动画结束后:

@Override

public void onAnimationEnd(Animator animation) {

//更新底部数据

showTotalPrice(entity);

// 把移动的图片imageview从父布局里移除

rl.removeView(goods);

}

@Override

public void onAnimationCancel(Animator animation) {

}

@Override

public void onAnimationRepeat(Animator animation) {

}

});

}

右侧列表减-

/**

* 购物车减

*

* @param view

* @param position

*/

@Override

public void remove(View view, int position, ProductListEntity.ProductEntity en) {

showTotalPrice(en);

}

价格展示更新

/**

* 底部价格和数量显示

*/

private void showTotalPrice(ProductListEntity.ProductEntity entity) {

if (shopCart != null && shopCart.getShoppingTotalPrice() > 0) {

tv_shopping_cart_money.setVisibility(View.VISIBLE);

tv_shopping_cart_money.setText("¥ " + shopCart.getShoppingTotalPrice());

tv_shopping_cart_count.setVisibility(View.VISIBLE);

//得到总的数量

int textCount = 0;

for (ProductListEntity.ProductEntity m : shopCart.getShoppingSingle().keySet()) {

Log.e("btn_shopping_cart_pay", "map集合中存储的数据---->" + m.getProductCount());

textCount += m.getProductCount();

}

tv_shopping_cart_count.setText("" + textCount);

} else {

tv_shopping_cart_money.setVisibility(View.INVISIBLE);

tv_shopping_cart_count.setVisibility(View.GONE);

}

updateLeftCount(entity);

}

到了这里右侧商品列表加和减还有加的动画效果就完成了,接下来就是右侧增加或者减少,怎么来改变左侧的角标显示

左侧角标改变方法这里要注意的是

注意

有人可以在上边数据结构商品的对象中看到

ParentId

这个字段,有人可能会问这个有需要吗,但是这个ID确实在这里用到了,当然可能也有其他的实现方法可能不需要这个字段,这里是通过子项中的父级ID和左侧列表中的ID来进行比对的,比对一致则说明我操作的数据属于左侧这一组中

/**

* 更新左侧数字角标(暂时不包含清空),触发更新肯定是在加或者减的时候触发,根据子项中的父ID和左侧ID比对,

*/

private void updateLeftCount(ProductListEntity.ProductEntity entity) {

if (shopCart != null) {

//加和减的时候要知道是那个左侧下边的,知道下标获取父id,然后从map中取count

if (entity != null) {

Log.e("updateLeftCount", "-------parentId:" + entity.getParentId() + "---------count:" + shopCart.getParentCountMap().get(entity.getParentId()));

leftAdapter.setUpdateMenuCount(entity.getParentId(), shopCart.getParentCountMap().get(entity.getParentId()));

}

if (rightAdapter != null) rightAdapter.notifyDataSetChanged();//跟新列表

}

}

LeftProductTypeAdapter中设置setUpdateMenuCount()方法

/**

* 更新左侧角标,需要知道那个对象

*

* @param

*/

public void setUpdateMenuCount(String parentId, int mUpdateParentCount) {

//需要实体数据保存更新

this.mUpdateParentId = parentId;

this.mUpdateParentCount = mUpdateParentCount;

notifyDataSetChanged();

this.clearCount = false;

}

同时在onBindViewHolder中判断设置大于0才显示

@Override

public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

ProductListEntity dishMenu = mMenuList.get(position);

LeftMenuViewHolder viewHolder = (LeftMenuViewHolder) holder;

viewHolder.menuName.setText(dishMenu.getTypeName());

if (mSelectedNum == position) {

viewHolder.menuLayout.setSelected(true);

} else {

viewHolder.menuLayout.setSelected(false);

}

if (dishMenu.getTypeId().equals(mUpdateParentId)) {//选中的ID

//更改数据

dishMenu.setTypeCount(mUpdateParentCount);

}

if (clearCount) {//隐藏所有数据,设置count都为0

viewHolder.tv_left_menu_count.setVisibility(View.GONE);

dishMenu.setTypeCount(0);

} else {

viewHolder.tv_left_menu_count.setVisibility(View.VISIBLE);

viewHolder.tv_left_menu_count.setText(dishMenu.getTypeCount() + "");

dishMenu.setTypeCount(dishMenu.getTypeCount());

}

if (dishMenu.getTypeCount() > 0) {//展示

viewHolder.tv_left_menu_count.setVisibility(View.VISIBLE);

viewHolder.tv_left_menu_count.setText(dishMenu.getTypeCount() + "");

} else {//隐藏

viewHolder.tv_left_menu_count.setVisibility(View.GONE);

}

}

到这里右侧加减操作,左侧角标也对应变化展示了,最后就是购物车弹窗

展示底部购物车

展示底部购物车这里使用了XPopup,可以自己引入,也可以引我项目中的poplibrary库,和meituanshoppingcart同级了

底部购物车展示

上面说的显示当前屏幕的百分之七十高度就是在这里设置的

Log.e("getWindowHeight", "---------height:" + Tool.getWindowHeight(MainActivity.this));

//获取屏幕的高度,然后拿到百分之70

int popHeight = (int) (Tool.getWindowHeight(MainActivity.this) * 0.7);

if (shopCart != null && shopCart.getShoppingAccount() > 0) {

new XPopup.Builder(MainActivity.this)

.atView(view)

.maxHeight(popHeight)

.isRequestFocus(false)

.asCustom(new CustomPartShadowPopupView(MainActivity.this, shopCart))

.show();

}

CustomPartShadowPopupView

/**

* @className: CustomPartShadowPopupView

* @description:

* @author: dingchao

* @time: 2020-11-19 15:13

*/

public class CustomPartShadowPopupView extends PartShadowPopupView implements ShopCartImp, View.OnClickListener {

private ListView lv_pop_list;

private Context context;

private ShopCart shopCart;

private TextView tv_shopping_cart_clear_all;

private TextView tv_shopping_cart_top_key_v;

ShoppingCartAdapter shoppingCartAdapter;

public CustomPartShadowPopupView(@NonNull Context context, ShopCart shopCart) {

super(context);

this.context = context;

this.shopCart = shopCart;

}

@Override

protected int getImplLayoutId() {

return R.layout.pop_shopping_cart;

}

@Override

protected void onCreate() {

super.onCreate();

initListener();

initDataViewBind();

}

/**

* 控件初始绑定

*/

private void initListener() {

lv_pop_list = findViewById(R.id.lv_pop_list);

tv_shopping_cart_clear_all = findViewById(R.id.tv_shopping_cart_clear_all);

tv_shopping_cart_top_key_v = findViewById(R.id.tv_shopping_cart_top_key_v);

tv_shopping_cart_clear_all.setOnClickListener(this);

}

/**

* 初始数据绑定及操作

*/

private void initDataViewBind() {

//数据绑定及展示

shoppingCartAdapter = new ShoppingCartAdapter(context, shopCart);

lv_pop_list.setAdapter(shoppingCartAdapter);

shoppingCartAdapter.setShopCartImp(this);

updateShoppingCartNum();

}

@Override

protected void onShow() {

super.onShow();

}

@Override

protected void onDismiss() {

super.onDismiss();

}

@Override

public void add(View view, int postion, ProductListEntity.ProductEntity entity) {

updateShoppingCartNum();

EventBus.getDefault().post(new EventBusShoppingEntity(entity, "add"));

}

/**

* 更新数字

*/

private void updateShoppingCartNum() {

if (shopCart != null) {

int textCount = 0;

for (ProductListEntity.ProductEntity m : shopCart.getShoppingSingle().keySet()) {

Log.e("btn_shopping_cart_pay", "map集合中存储的数据---->" + m.getProductCount());

textCount += m.getProductCount();

}

tv_shopping_cart_top_key_v.setText("(共" + textCount + "件商品)");

}

}

@Override

public void remove(View view, int postion, ProductListEntity.ProductEntity entity) {

//判读count是不是到0了,到0说明没数据了,如果购物车弹窗开着,则关闭

updateShoppingCartNum();

EventBus.getDefault().post(new EventBusShoppingEntity(entity, "reduce"));

if (shopCart != null && shopCart.getShoppingAccount() == 0) {

this.dismiss();

}

}

@Override

public void onClick(View view) {

switch (view.getId()) {

case R.id.tv_shopping_cart_clear_all:

//清空

shopCart.clear();

this.dismiss();

updateShoppingCartNum();

EventBus.getDefault().post(new EventBusShoppingEntity(null, "clearAll"));

break;

default:

break;

}

}

}

这里使用了EventBus来进行通知Activity来通知更新右侧列表数量和左侧列表的角标更新

对应的接受方法

//定义处理接收的方法

@Subscribe(threadMode = ThreadMode.MAIN)

public void onEvent(EventBusShoppingEntity entity) {

if (entity.getKey().equals("add")) {

showTotalPrice(entity.getEntity());

} else if (entity.getKey().equals("reduce")) {

showTotalPrice(entity.getEntity());

} else if (entity.getKey().equals("clearAll")) {//清空全部

clearCartDataAndListData();

}

}

最后就是清空数据和提交时提交的数据

清空

/**

* 清空购物车及左侧列表都角标和商品列表

*/

private void clearCartDataAndListData() {

shopCart.clear();

shopCart.getParentCountMap().clear();

showTotalPrice(null);

//左侧清空

leftAdapter.setClearCount();

}

提交

//结算的商品列表

ToastUtil.showShort(MainActivity.this, "dianjile");

if (shopCart.getShoppingSingle().size() > 0) {

List commitListData = new ArrayList<>();

for (ProductListEntity.ProductEntity m : shopCart.getShoppingSingle().keySet()) {

Log.e("btn_cart_pay", "map集合中存储的数据---->" + m.getProductCount());

commitListData.add(m);

}

for (int i = 0; i < commitListData.size(); i++) {

Log.e("btn_cart_pay_list", "commitList---->" + commitListData.get(i));

}

Log.e("btn_cart_pay_list_JSON", "commitList---->" + JSON.toJSONString(commitListData));

}

这里提交的数据其实就是改变了count的对象,由于后台要快照,所以会要求我们给传递数据,所以咋回来的,咋在给他们就完了,只把最后的数量更改提交就可以了。

提交的例子

[{

"parentId": "1",

"productCount": 2,

"productId": "1",

"productImg": "img地址",

"productMoney": 10.0,

"productMonth": "34",

"productName": "新上市猕猴桃1-1"

}, {

"parentId": "1",

"productCount": 1,

"productId": "4",

"productImg": "img地址",

"productMoney": 40.0,

"productMonth": "34",

"productName": "新上市猕猴桃4-1"

}]

以上就是仿美团双列表添加购物车交互的效果的大体代码和逻辑,说的可能比较乱,需要完整代码的可以去上面地址找

meituanshoppingcart

项目自己下载一下,代码挺简单的,注释也写了不算少,代码还没进行优化处理,效果和基本的思路是这样的,如果有这种效果更好的实现思路和方法的也欢迎各位大神指教,共同进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值