先看下效果圖:

ezgif-1-8f133ca916.gif
1.首先列表布局采用Recycleview
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v7.widget.RecyclerView>
<LinearLayout
android:background="#fff"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_shop_cart"
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="2dp"
android:src="@mipmap/icon_shop_shopcart"/>
<TextView
android:visibility="gone"
android:gravity="center"
android:text="11"
android:id="@+id/tv_num"
android:textColor="#fff"
android:layout_gravity="right"
android:background="@drawable/cart_num"
android:layout_width="20dp"
android:layout_height="20dp"/>
</FrameLayout>
<View
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1"/>
<TextView
android:layout_width="80dp"
android:layout_height="30dp"
android:layout_marginRight="6dp"
android:background="#f17334"
android:gravity="center"
android:text="購(gòu)買(mǎi)"
android:textColor="#ffffff"/>
</LinearLayout>
</RelativeLayout>
2.購(gòu)物車(chē)item布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="120dp"
android:background="#fff"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv"
android:layout_width="120dp"
android:layout_height="120dp"
android:src="@mipmap/icon_shop_goods"/>
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_toRightOf="@+id/iv"
android:text="麻辣牛肉粉"
android:textColor="#000"/>
<TextView
android:id="@+id/tv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_toRightOf="@+id/iv"
android:text="精選上等黃牛肉,加上特制秘方..."
android:textSize="12sp"/>
<TextView
android:id="@+id/tv3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv2"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_toRightOf="@+id/iv"
android:background="@drawable/shape_discount"
android:paddingLeft="4dp"
android:paddingRight="2dp"
android:text="8折"
android:textColor="#fff"
android:textSize="12sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv2"
android:layout_marginTop="10dp"
android:layout_toRightOf="@+id/tv3"
android:background="@drawable/shape_users"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:text="餓了么vip專享"
android:textColor="#fff"
android:textSize="12sp"/>
<TextView
android:id="@+id/tv_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginLeft="10dp"
android:layout_marginTop="40dp"
android:layout_toRightOf="@+id/iv"
android:text="¥19.99元"
android:textColor="#ff00"/>
<TextView
android:id="@+id/tv_old"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@id/tv_price"
android:layout_marginLeft="5dp"
android:text="¥28.50元"
android:textSize="13sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/iv_reduce"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_alignBottom="@+id/tv_price"
android:layout_toLeftOf="@+id/tvamount"
android:src="@mipmap/icon_shop_reduce"/>
<TextView
android:id="@+id/tvamount"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_alignBottom="@+id/tv_price"
android:layout_centerInParent="true"
android:layout_toLeftOf="@+id/iv_add"
android:gravity="center"
android:text="1"
android:textColor="#000"/>
<ImageView
android:id="@+id/iv_add"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_alignBottom="@+id/tv_price"
android:layout_alignParentRight="true"
android:layout_marginRight="10dp"
android:src="@mipmap/icon_shop_add"/>
</RelativeLayout>
3.點(diǎn)擊加號(hào)操作這里分二鐘情況一是當(dāng)數(shù)量為0時(shí)減號(hào)會(huì)執(zhí)行旋轉(zhuǎn)和平移漸變的動(dòng)畫(huà),二是數(shù)量不為0時(shí)只會(huì)進(jìn)行拋物線動(dòng)畫(huà),其中拋物線動(dòng)畫(huà)實(shí)現(xiàn)思路就是得到加號(hào)和購(gòu)物車(chē)的坐標(biāo),然后得到最外層容器添加一個(gè)view來(lái)執(zhí)行這個(gè)動(dòng)畫(huà),動(dòng)畫(huà)執(zhí)行完成后移除這個(gè)動(dòng)畫(huà):
//得到加號(hào)在屏幕的坐標(biāo)
int[] addLocation = new int[2];
v.getLocationInWindow(addLocation);
//得到購(gòu)物車(chē)圖標(biāo)的坐標(biāo)
int[] cartLocation = mActivity.getCartLocation();
//添加一個(gè)imageview
final ImageView iv = new ImageView(v.getContext());
iv.setBackgroundResource(R.mipmap.icon_shop_add);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(v.getWidth(), v.getHeight());
lp.leftMargin = addLocation[0];
lp.topMargin = addLocation[1] - v.getHeight();
mActivity.getContainer().addView(iv, lp);
//橫向移動(dòng)
ObjectAnimator oaX = ObjectAnimator.ofFloat(iv, "translationX", cartLocation[0] - addLocation[0] + v.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();
4.完整代碼:
private RecyclerView mRecyclerView;
private ImageView mIvCart;
private RelativeLayout mContainer;
private TextView mtvNum;
public int mCount = 0;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_shopping_cart);
mRecyclerView = findViewById(R.id.rv);
mIvCart = findViewById(R.id.iv_shop_cart);
mContainer = findViewById(R.id.container);
mtvNum = findViewById(R.id.tv_num);
final List<CartModel> list = new ArrayList<>();
for (int i = 0; i < 20; i++) {
CartModel cartModel = new CartModel();
cartModel.setName("紅燒牛肉面" + i);
list.add(cartModel);
}
final ShoppingAdapter shoppingAdapter = new ShoppingAdapter(this, list);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));
mRecyclerView.setAdapter(shoppingAdapter);
//購(gòu)物車(chē)點(diǎn)擊事件的回調(diào)
}
/**
* 得到布局最外層
*
* @return
*/
public RelativeLayout getContainer() {
return this.mContainer;
}
/**
* 得到購(gòu)物車(chē)在窗體上的坐標(biāo)
*
* @return
*/
public int[] getCartLocation() {
int[] cartLocation = new int[2];
mIvCart.getLocationInWindow(cartLocation);
return cartLocation;
}
public void setMtvNum() {
if (mCount > 0) {
mtvNum.setText(String.valueOf(mCount));
mtvNum.setVisibility(View.VISIBLE);
}else {
mtvNum.setVisibility(View.GONE);
}
}
private List<CartModel> mDatas;
private int mAmountLeft;
private int mReduceLeft;
private int mAddLeft;
private ShoppingCartActivity mActivity;
public ShoppingAdapter(Activity activity, List<CartModel> list) {
mDatas = list;
this.mActivity = (ShoppingCartActivity) activity;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_shopping_cart, parent, false);
MyHolder holder = new MyHolder(view);
return holder;
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
final MyHolder myHolder = (MyHolder) holder;
myHolder.setItem(position);
//點(diǎn)擊加號(hào)
myHolder.imageViewAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final CartModel cartModel = mDatas.get(position);
//如果該商品數(shù)量為0就進(jìn)行這個(gè)動(dòng)畫(huà)
if (cartModel.getCount() == 0) {
myHolder.imageViewReduce.setVisibility(View.VISIBLE);
myHolder.tvAmount.setVisibility(View.VISIBLE);
AnimatorSet set = new AnimatorSet();
//減號(hào)
ObjectAnimator ta1 = ObjectAnimator.ofFloat(myHolder.imageViewReduce, "translationX", mAddLeft - mReduceLeft, 0);
ObjectAnimator ra1 = ObjectAnimator.ofFloat(myHolder.imageViewReduce, "rotation", 0, 360);
ObjectAnimator aa1 = ObjectAnimator.ofFloat(myHolder.imageViewReduce, "alpha", 0, 1);
//數(shù)字
ObjectAnimator ta2 = ObjectAnimator.ofFloat(myHolder.tvAmount, "translationX", mAddLeft - mAmountLeft, 0);
ObjectAnimator ra2 = ObjectAnimator.ofFloat(myHolder.tvAmount, "rotation", 0, 360);
ObjectAnimator aa2 = ObjectAnimator.ofFloat(myHolder.tvAmount, "alpha", 0, 1);
set.play(ta1).with(ra1).with(ta2).with(ra2).with(aa1).with(aa2);
set.setDuration(500).start();
}
//addGoods2CartAnim((ImageView) v,cartModel);
//得到加號(hào)在屏幕的坐標(biāo)
int[] addLocation = new int[2];
v.getLocationInWindow(addLocation);
//得到購(gòu)物車(chē)圖標(biāo)的坐標(biāo)
int[] cartLocation = mActivity.getCartLocation();
//添加一個(gè)imageview
final ImageView iv = new ImageView(v.getContext());
iv.setBackgroundResource(R.mipmap.icon_shop_add);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(v.getWidth(), v.getHeight());
lp.leftMargin = addLocation[0];
lp.topMargin = addLocation[1] - v.getHeight();
mActivity.getContainer().addView(iv, lp);
//橫向移動(dòng)
ObjectAnimator oaX = ObjectAnimator.ofFloat(iv, "translationX", cartLocation[0] - addLocation[0] + v.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) {}
@Override
public void onAnimationEnd(Animator animation) {
//移除這個(gè)view
mActivity.getContainer().removeView(iv);
//跟新購(gòu)物車(chē)
cartModel.setCount(cartModel.getCount() + 1);
((MyHolder) holder).tvAmount.setText(String.valueOf(cartModel.getCount()));
mActivity.mCount++;
mActivity.setMtvNum();
}
@Override
public void onAnimationCancel(Animator animation) {}
@Override
public void onAnimationRepeat(Animator animation) {}
});
}
});
//點(diǎn)擊減號(hào)
myHolder.imageViewReduce.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final CartModel cartModel = mDatas.get(position);
//如果該商品數(shù)量為1就進(jìn)行這個(gè)動(dòng)畫(huà)
if (cartModel.getCount() == 1) {
AnimatorSet set = new AnimatorSet();
//減號(hào)
ObjectAnimator ta1 = ObjectAnimator.ofFloat(myHolder.imageViewReduce, "translationX", 0, mAddLeft - mReduceLeft);
ObjectAnimator ra1 = ObjectAnimator.ofFloat(myHolder.imageViewReduce, "rotation", 0, 360);
ObjectAnimator aa1 = ObjectAnimator.ofFloat(myHolder.imageViewReduce, "alpha", 1, 0);
//數(shù)字
ObjectAnimator ta2 = ObjectAnimator.ofFloat(myHolder.tvAmount, "translationX", 0, mAddLeft - mAmountLeft);
ObjectAnimator ra2 = ObjectAnimator.ofFloat(myHolder.tvAmount, "rotation", 0, 360);
ObjectAnimator aa2 = ObjectAnimator.ofFloat(myHolder.tvAmount, "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) {}
@Override
public void onAnimationEnd(Animator animation) {
cartModel.setCount(cartModel.getCount() - 1);
myHolder.tvAmount.setText(String.valueOf(cartModel.getCount()));
if(cartModel.getCount()==0){
myHolder.tvAmount.setVisibility(View.INVISIBLE);
myHolder.imageViewReduce.setVisibility(View.INVISIBLE);
}
mActivity.mCount--;
mActivity.setMtvNum();
}
@Override
public void onAnimationCancel(Animator animation) {}
@Override
public void onAnimationRepeat(Animator animation) {}
});
} else {
cartModel.setCount(cartModel.getCount() - 1);
myHolder.tvAmount.setText(String.valueOf(cartModel.getCount()));
mActivity.mCount--;
mActivity.setMtvNum();
}
}
});
}
@Override
public int getItemCount() {
return mDatas.size();
}
class MyHolder extends RecyclerView.ViewHolder {
TextView title;
ImageView imageViewAdd;
ImageView imageViewReduce;
TextView tvAmount;
TextView tvOld;
public MyHolder(View itemView) {
super(itemView);
title = itemView.findViewById(R.id.tv);
imageViewAdd = itemView.findViewById(R.id.iv_add);
imageViewReduce = itemView.findViewById(R.id.iv_reduce);
tvAmount = itemView.findViewById(R.id.tvamount);
tvOld = itemView.findViewById(R.id.tv_old);
tvOld.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG);
imageViewAdd.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//得到加號(hào)的左邊位置
mAddLeft = imageViewAdd.getLeft();
imageViewAdd.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
imageViewReduce.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//得到減號(hào)的左邊位置
mReduceLeft = imageViewReduce.getLeft();
imageViewReduce.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
tvAmount.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//得到價(jià)格的左邊位置
mAmountLeft = tvAmount.getLeft();
tvAmount.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
}
public void setItem(int position) {
CartModel cartModel = mDatas.get(position);
title.setText(cartModel.getName());
tvAmount.setText(String.valueOf(cartModel.getCount()));
if (cartModel.getCount() > 0) {//數(shù)目大于0就顯示
imageViewReduce.setVisibility(View.VISIBLE);
tvAmount.setVisibility(View.VISIBLE);
} else {//數(shù)目小于0就隱藏
imageViewReduce.setVisibility(View.INVISIBLE);
tvAmount.setVisibility(View.INVISIBLE);
}
}
}