這篇文章將為大家詳細(xì)講解有關(guān)Android怎么實(shí)現(xiàn)購(gòu)物車(chē)添加商品動(dòng)畫(huà),小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
創(chuàng)新互聯(lián)是專(zhuān)業(yè)的彭澤網(wǎng)站建設(shè)公司,彭澤接單;提供成都網(wǎng)站建設(shè)、成都做網(wǎng)站,網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專(zhuān)業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行彭澤網(wǎng)站開(kāi)發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專(zhuān)業(yè)做搜索引擎喜愛(ài)的網(wǎng)站,專(zhuān)業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!
實(shí)現(xiàn)需求:
在商品列表頁(yè)面,從列表Item 添加商品的時(shí)候,需要一個(gè)動(dòng)畫(huà),仿佛是是往購(gòu)物車(chē)?yán)锾砑由唐贰?/p>
實(shí)現(xiàn)思路:
獲取起始點(diǎn)與終點(diǎn)的坐標(biāo),利用PathMeasure 繪制貝塞爾曲線;
為點(diǎn)擊的Item 商品View 設(shè)置屬性動(dòng)畫(huà);
監(jiān)聽(tīng)屬性動(dòng)畫(huà)的update,改變View 的坐標(biāo);
實(shí)現(xiàn)效果:

實(shí)現(xiàn)中會(huì)用到 PathMeasure 類(lèi):
我們主要使用它兩個(gè)方法:
1、獲取長(zhǎng)度:
/** //獲取弧線的總長(zhǎng)度(周長(zhǎng))
* Return the total length of the current contour, or 0 if no path is
* associated with this measure object.
*/
public float getLength() {
return native_getLength(native_instance);//系統(tǒng)調(diào)用native 方法;
}2、獲取坐標(biāo):
/**
* Pins distance to 0 <= distance <= getLength(), and then computes the
* corresponding position and tangent. Returns false if there is no path,
* or a zero-length path was specified, in which case position and tangent
* are unchanged.
*
* @param distance The distance along the current contour to sample
* @param pos If not null, eturns the sampled position (x==[0], y==[1])
* @param tan If not null, returns the sampled tangent (x==[0], y==[1])
* @return false if there was no path associated with this measure object
*/
public boolean getPosTan(float distance, float pos[], float tan[]) {
if (pos != null && pos.length < 2 ||
tan != null && tan.length < 2) {
throw new ArrayIndexOutOfBoundsException();
}
return native_getPosTan(native_instance, distance, pos, tan);
}方法 getPosTan(float distance, float pos[],float tan[]) - path 為 null ,返回 false
distance 為一個(gè) 0 - getLength() 之間的值,根據(jù)這個(gè)值 PathMeasure 會(huì)計(jì)算出當(dāng)前點(diǎn)的坐標(biāo)封裝到 pos 中。上面這句話我們可以這么來(lái)理解,不管實(shí)際 Path 多么的復(fù)雜,PathMeasure 都相當(dāng)于做了一個(gè)事情,就是把 Path “拉直”,然后給了我們一個(gè)接口(getLength)告訴我們path的總長(zhǎng)度,然后我們想要知道具體某一點(diǎn)的坐標(biāo),只需要用相對(duì)的distance去取即可,這樣就省去了自己用函數(shù)模擬path,然后計(jì)算獲取點(diǎn)坐標(biāo)的過(guò)程。
代碼如下:
public class GoodsListActivity extends AppCompatActivity {
private RelativeLayout mRootRl;
private RecyclerView mGoodsRecyclerView;
private ImageView mCarImageView;
private TextView mCountTv;
private List<Bitmap> mBitmapList = new ArrayList<>();
private PathMeasure mPathMeasure;
private float[] mCurrentPosition = new float[2];
private int mCount = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_goods_list);
initView();
initData();
GoodsAdapter goodsAdapter = new GoodsAdapter(mBitmapList);
mGoodsRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mGoodsRecyclerView.setAdapter(goodsAdapter);
}
private void initView(){
mGoodsRecyclerView = (RecyclerView)findViewById(R.id.recyclerView);
mCarImageView = (ImageView)findViewById(R.id.imageview_shop_car);
mCountTv = (TextView)findViewById(R.id.tv_count);
mRootRl = (RelativeLayout)findViewById(R.id.rl_root);
}
private void initData(){
mBitmapList.add(BitmapFactory.decodeResource(getResources(), R.drawable.car));
mBitmapList.add(BitmapFactory.decodeResource(getResources(), R.drawable.car));
mBitmapList.add(BitmapFactory.decodeResource(getResources(), R.drawable.car));
}
class GoodsAdapter extends RecyclerView.Adapter<GoodsViewHolder>{
private List<Bitmap> mData;
public GoodsAdapter(List<Bitmap> data) {
mData = data;
}
@Override
public GoodsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(GoodsListActivity.this)
.inflate(R.layout.rv_goods_item, parent, false);
return new GoodsViewHolder(itemView);
}
@Override
public void onBindViewHolder(final GoodsViewHolder holder, int position) {
holder.ivGood.setImageBitmap(mData.get(position));
holder.tvBuy.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
addGoodToCar(holder.ivGood);
}
});
}
@Override
public int getItemCount() {
return mData != null ? mData.size() : 0;
}
}
private void addGoodToCar(ImageView imageView){
final ImageView view = new ImageView(GoodsListActivity.this);
view.setImageDrawable(imageView.getDrawable());
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(100, 100);
mRootRl.addView(view, layoutParams);
//二、計(jì)算動(dòng)畫(huà)開(kāi)始/結(jié)束點(diǎn)的坐標(biāo)的準(zhǔn)備工作
//得到父布局的起始點(diǎn)坐標(biāo)(用于輔助計(jì)算動(dòng)畫(huà)開(kāi)始/結(jié)束時(shí)的點(diǎn)的坐標(biāo))
int[] parentLoc = new int[2];
mRootRl.getLocationInWindow(parentLoc);
//得到商品圖片的坐標(biāo)(用于計(jì)算動(dòng)畫(huà)開(kāi)始的坐標(biāo))
int startLoc[] = new int[2];
imageView.getLocationInWindow(startLoc);
//得到購(gòu)物車(chē)圖片的坐標(biāo)(用于計(jì)算動(dòng)畫(huà)結(jié)束后的坐標(biāo))
int endLoc[] = new int[2];
mCarImageView.getLocationInWindow(endLoc);
float startX = startLoc[0] - parentLoc[0] + imageView.getWidth()/2;
float startY = startLoc[1] - parentLoc[1] + imageView.getHeight()/2;
//商品掉落后的終點(diǎn)坐標(biāo):購(gòu)物車(chē)起始點(diǎn)-父布局起始點(diǎn)+購(gòu)物車(chē)圖片的1/5
float toX = endLoc[0] - parentLoc[0] + mCarImageView.getWidth() / 5;
float toY = endLoc[1] - parentLoc[1];
//開(kāi)始繪制貝塞爾曲線
Path path = new Path();
path.moveTo(startX, startY);
//使用二次薩貝爾曲線:注意第一個(gè)起始坐標(biāo)越大,貝塞爾曲線的橫向距離就會(huì)越大,一般按照下面的式子取即可
path.quadTo((startX + toX) / 2, startY, toX, toY);
mPathMeasure = new PathMeasure(path, false);
//屬性動(dòng)畫(huà)
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, mPathMeasure.getLength());
valueAnimator.setDuration(1000);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float)animation.getAnimatedValue();
mPathMeasure.getPosTan(value, mCurrentPosition, null);
view.setTranslationX(mCurrentPosition[0]);
view.setTranslationY(mCurrentPosition[1]);
}
});
valueAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
// 購(gòu)物車(chē)的數(shù)量加1
mCount++;
mCountTv.setText(String.valueOf(mCount));
// 把移動(dòng)的圖片imageview從父布局里移除
mRootRl.removeView(view);
//shopImg 開(kāi)始一個(gè)放大動(dòng)畫(huà)
Animation scaleAnim = AnimationUtils.loadAnimation(GoodsListActivity.this, R.anim.shop_car_scale);
mCarImageView.startAnimation(scaleAnim);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
valueAnimator.start();
}
class GoodsViewHolder extends RecyclerView.ViewHolder{
private ImageView ivGood;
private TextView tvBuy;
public GoodsViewHolder(View itemView) {
super(itemView);
ivGood = (ImageView)itemView.findViewById(R.id.iv_goods);
tvBuy = (TextView) itemView.findViewById(R.id.tv_buy);
}
}
}關(guān)于“Android怎么實(shí)現(xiàn)購(gòu)物車(chē)添加商品動(dòng)畫(huà)”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
本文題目:Android怎么實(shí)現(xiàn)購(gòu)物車(chē)添加商品動(dòng)畫(huà)
分享地址:http://www.chinadenli.net/article22/piejjc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站導(dǎo)航、網(wǎng)站排名、網(wǎng)站收錄、移動(dòng)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)公司、
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)