購物車功能在電商項(xiàng)目中可以說是一個(gè)必不可少的功能了,但是在項(xiàng)目當(dāng)中我們還是想將這個(gè)功能給盡可能的做的好看點(diǎn)、可觀賞性強(qiáng)一點(diǎn),所以我們便把目光投向了餓了么,畢竟那個(gè)動(dòng)畫還是挺好看的呢,這里先上布局文件看下效果
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_F4F4F4"
android:orientation="vertical">
<include layout="@layout/app_title_bar" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.3"
android:gravity="center"
android:text="我是商品分類"
android:textColor="@color/colorBlack"
android:textSize="12sp"
tools:ignore="HardcodedText,NestedWeights" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.7"
android:background="@color/colorWhite" />
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="55dp"
android:paddingStart="16dp"
android:paddingEnd="16dp">
<TextView
android:id="@+id/tv_sum_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="70dp"
android:text="請(qǐng)?zhí)砑由唐?
android:textColor="@color/colorHint"
android:textSize="14sp" />
<TextView
android:id="@+id/tv_settlement"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:background="@drawable/btn_main_sure"
android:paddingStart="18dp"
android:paddingTop="9dp"
android:paddingEnd="18dp"
android:paddingBottom="9dp"
android:text="結(jié)算"
android:textColor="@color/colorWhite"
android:textSize="14sp" />
</RelativeLayout>
</LinearLayout>
<RelativeLayout
android:id="@+id/layout_cart"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_alignParentBottom="true">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon_cart_left_bottom" />
<TextView
android:id="@+id/tv_cart_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:background="@drawable/bg_main_cart_number"
android:paddingStart="6dp"
android:paddingTop="2dp"
android:paddingEnd="6dp"
android:paddingBottom="2dp"
android:textColor="@color/colorWhite"
android:textSize="12sp"
android:visibility="gone"
tools:text="14"
tools:visibility="visible" />
</RelativeLayout>
</RelativeLayout>
</LinearLayout>

布局效果展示
接下來就是我們自定義的adapter
public class CartGoodsAdapter extends RecyclerView.Adapter {
private final List<CartGoodsBean> mData;
private int mAmountLeft;
private int mReduceLeft;
private int mAddLeft;
private final CartDetailUI cartActivity;
private final Context mContext;
public CartGoodsAdapter(Activity activity, Context mContext, List<CartGoodsBean> list) {
mData = list;
this.cartActivity = (CartDetailUI) activity;
this.mContext = mContext;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_cart_goods,
parent, false);
return new MyHolder(view);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
final MyHolder myHolder = (MyHolder) holder;
myHolder.setItem(position);
final CartGoodsBean goodsBean = mData.get(position);
myHolder.itemName.setText(goodsBean.getGoodsName());
myHolder.itemSku.setText(goodsBean.getSku());
myHolder.itemPrice.setText(StringUtils.formatDouble(goodsBean.getSellPrice(), true));
final long[] clickTime = {0};
//點(diǎn)擊加號(hào)
myHolder.itemPlus.setOnClickListener(view -> {
//屏蔽快速點(diǎn)擊加入購物車問題
if (System.currentTimeMillis() - clickTime[0] <= 1000) {
return;
}
clickTime[0] = System.currentTimeMillis();
if (goodsBean.getCount() >= goodsBean.getStoreNumber()) {
ToastUtils.showToast(mContext, "商品庫存不足");
return;
}
//如果該商品數(shù)量為0就進(jìn)行 該動(dòng)畫
if (goodsBean.getCount() == 0) {
myHolder.itemMinus.setVisibility(View.VISIBLE);
myHolder.itemCartNumber.setVisibility(View.VISIBLE);
AnimatorSet set = new AnimatorSet();
//減號(hào)
ObjectAnimator ta1 = ObjectAnimator.ofFloat(myHolder.itemMinus,
"translationX", mAddLeft - mReduceLeft, 0);
ObjectAnimator ra1 = ObjectAnimator.ofFloat(myHolder.itemMinus,
"rotation", 0, 360);
ObjectAnimator aa1 = ObjectAnimator.ofFloat(myHolder.itemMinus,
"alpha", 0, 1);
//數(shù)字
ObjectAnimator ta2 = ObjectAnimator.ofFloat(myHolder.itemCartNumber,
"translationX", mAddLeft - mAmountLeft, 0);
ObjectAnimator ra2 = ObjectAnimator.ofFloat(myHolder.itemCartNumber,
"rotation", 0, 360);
ObjectAnimator aa2 = ObjectAnimator.ofFloat(myHolder.itemCartNumber,
"alpha", 0, 1);
set.play(ta1).with(ra1).with(ta2).with(ra2).with(aa1).with(aa2);
set.setDuration(500).start();
}
//得到加號(hào)在屏幕的坐標(biāo)
int[] addLocation = new int[2];
view.getLocationInWindow(addLocation);
//得到購物車圖標(biāo)的坐標(biāo)
int[] cartLocation = cartActivity.getCartLocation();
//添加一個(gè)imageview
final ImageView iv = new ImageView(view.getContext());
iv.setBackgroundResource(R.drawable.icon_plus);
RelativeLayout.LayoutParams lp =
new RelativeLayout.LayoutParams(view.getWidth(), view.getHeight());
lp.leftMargin = addLocation[0];
lp.topMargin = addLocation[1] - view.getHeight();
cartActivity.getContainer().addView(iv, lp);
//橫向移動(dòng)
ObjectAnimator oaX = ObjectAnimator.ofFloat(iv, "translationX",
cartLocation[0] - addLocation[0] + view.getWidth() / 2);
//縱向
ObjectAnimator oaY = ObjectAnimator.ofFloat(iv,
"translationY", cartLocation[1] - addLocation[1]);
oaX.setInterpolator(new LinearInterpolator());
oaY.setInterpolator(new AccelerateInterpolator());
AnimatorSet set = new AnimatorSet();
set.play(oaX).with(oaY);
set.setDuration(500).start();
set.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@SuppressLint("NotifyDataSetChanged")
@Override
public void onAnimationEnd(Animator animation) {
//移除這個(gè)view
cartActivity.getContainer().removeView(iv);
//更新購物車
goodsBean.setCount(goodsBean.getCount() + 1);
if (cartActivity.cartList.size() > 0) {
for (int i = 0; i < cartActivity.cartList.size(); i++) {
if (cartActivity.cartList.get(i).getSkuId() == goodsBean.getSkuId()) {
cartActivity.cartList.get(i).setCount(goodsBean.getCount());
break;
} else if (i == cartActivity.cartList.size() - 1) {
cartActivity.cartList.add(goodsBean);
break;
}
}
} else {
cartActivity.cartList.add(goodsBean);
}
((MyHolder) holder).itemCartNumber.setText(String.valueOf(goodsBean.getCount()));
cartActivity.mCount++;
cartActivity.setCartNumber();
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
});
//點(diǎn)擊減號(hào)
myHolder.itemMinus.setOnClickListener(view -> {
final CartGoodsBean cartModel = mData.get(position);
//如果該商品數(shù)量為1就進(jìn)行這個(gè)動(dòng)畫
if (cartModel.getCount() == 1) {
AnimatorSet set = new AnimatorSet();
//減號(hào)
ObjectAnimator ta1 = ObjectAnimator.ofFloat(myHolder.itemMinus,
"translationX", 0, mAddLeft - mReduceLeft);
ObjectAnimator ra1 = ObjectAnimator.ofFloat(myHolder.itemMinus,
"rotation", 0, 360);
ObjectAnimator aa1 = ObjectAnimator.ofFloat(myHolder.itemMinus,
"alpha", 1, 0);
//數(shù)字
ObjectAnimator ta2 = ObjectAnimator.ofFloat(myHolder.itemCartNumber,
"translationX", 0, mAddLeft - mAmountLeft);
ObjectAnimator ra2 = ObjectAnimator.ofFloat(myHolder.itemCartNumber,
"rotation", 0, 360);
ObjectAnimator aa2 = ObjectAnimator.ofFloat(myHolder.itemCartNumber,
"alpha", 1, 0);
set.play(ta1).with(ra1).with(ta2).with(ra2).with(aa1).with(aa2);
set.setDuration(500).start();
set.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@SuppressLint("NotifyDataSetChanged")
@Override
public void onAnimationEnd(Animator animation) {
cartModel.setCount(cartModel.getCount() - 1);
myHolder.itemCartNumber.setText(String.valueOf(cartModel.getCount()));
if (cartModel.getCount() == 0) {
myHolder.itemCartNumber.setVisibility(View.INVISIBLE);
myHolder.itemMinus.setVisibility(View.INVISIBLE);
}
if (cartActivity.cartList.size() > 0) {
for (int i = 0; i < cartActivity.cartList.size(); i++) {
if (cartActivity.cartList.get(i).getSkuId() == goodsBean.getSkuId()) {
if (cartActivity.cartList.get(i).getCount() == 0) {
cartActivity.cartList.remove(cartModel);
}
}
}
}
cartActivity.mCount--;
cartActivity.setCartNumber();
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
} else {
cartModel.setCount(cartModel.getCount() - 1);
if (cartActivity.cartList.size() > 0) {
for (int i = 0; i < cartActivity.cartList.size(); i++) {
if (cartActivity.cartList.get(i).getSkuId() == goodsBean.getSkuId()) {
cartActivity.cartList.get(i).setCount(cartModel.getCount());
}
}
}
myHolder.itemCartNumber.setText(String.valueOf(cartModel.getCount()));
cartActivity.mCount--;
cartActivity.setCartNumber();
}
});
}
@Override
public int getItemCount() {
return mData.size();
}
class MyHolder extends RecyclerView.ViewHolder {
ImageView itemImage;
TextView itemName, itemSku, itemPrice, itemCartNumber;
ImageButton itemMinus, itemPlus;
LinearLayout layoutAdd;
public MyHolder(View itemView) {
super(itemView);
itemImage = itemView.findViewById(R.id.item_image);
itemName = itemView.findViewById(R.id.item_name);
itemSku = itemView.findViewById(R.id.item_sku);
itemCartNumber = itemView.findViewById(R.id.item_cart_number);
layoutAdd = itemView.findViewById(R.id.layout_add);
itemMinus = itemView.findViewById(R.id.item_minus);
itemPrice = itemView.findViewById(R.id.item_price);
itemPlus = itemView.findViewById(R.id.item_plus);
itemPlus.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//得到加號(hào)的左邊位置
mAddLeft = itemPlus.getLeft();
itemPlus.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
itemMinus.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//得到減號(hào)的左邊位置
mReduceLeft = itemMinus.getLeft();
itemMinus.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
itemCartNumber.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//得到價(jià)格的左邊位置
mAmountLeft = itemCartNumber.getLeft();
itemCartNumber.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
}
public void setItem(int position) {
CartGoodsBean cartModel = mData.get(position);
itemName.setText(cartModel.getGoodsName());
itemCartNumber.setText(String.valueOf(cartModel.getCount()));
if (cartModel.getCount() > 0) {//數(shù)目大于0就顯示
itemMinus.setVisibility(View.VISIBLE);
itemCartNumber.setVisibility(View.VISIBLE);
} else {//數(shù)目小于0就隱藏
itemMinus.setVisibility(View.INVISIBLE);
itemCartNumber.setVisibility(View.INVISIBLE);
}
}
}
}
到這里其實(shí)已經(jīng)差不多完成了整個(gè)流程了,接下來在activity中進(jìn)行調(diào)用就可以獲取到我們所想要的功能了
goodsList.add(new CartGoodsBean(1, "紅豆奶茶", "餓了么專享", 15, 3));
goodsList.add(new CartGoodsBean(12, "楊枝甘露", "餓了么專享", 8, 1));
goodsList.add(new CartGoodsBean(666, "抹茶奶綠", "餓了么專享", 13.09, 7));
goodsList.add(new CartGoodsBean(101, "冰紅茶", "餓了么專享", 7.5, 10));
//商品列表
binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
cartGoodsAdapter = new CartGoodsAdapter(this, mContext, goodsList);
binding.recyclerView.setAdapter(cartGoodsAdapter);
}

加入購物車功能
最后我們需要做的是在點(diǎn)擊購物車圖標(biāo)的時(shí)候彈出購物車列表,這里我們我們直接貼上代碼
/**
* 展開購物車列表
*/
private void showCartDialog() {
/* 獲取屏幕信息 */
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int height;
if (cartList.size() > 4) {
height = displayMetrics.heightPixels / 2;
} else {
height = ViewGroup.LayoutParams.WRAP_CONTENT;
}
ShopCartDialog dialog = new ShopCartDialog(this, mContext, R.style.cartDialog);
Window window = dialog.getWindow();
dialog.setCancelable(true);
dialog.show();
WindowManager.LayoutParams params = window.getAttributes();
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.height = height;
params.gravity = Gravity.BOTTOM;
params.dimAmount = 0f;
window.setAttributes(params);
}

購物車列表效果