日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Android貝塞爾曲線實現加入購物車拋物線動畫_Android

作者:簡簡單單_zz ? 更新時間: 2022-08-21 編程語言

本文實例為大家分享了Android貝塞爾曲線實現加入購物車拋物線動畫的具體代碼,供大家參考,具體內容如下

先上圖看效果

步驟:

a.確定動畫的起終點
b.在起終點之間使用二次貝塞爾曲線填充起終點之間的點的軌跡
c.設置屬性動畫,ValueAnimator插值器,獲取中間點的坐標
d.將執行動畫的控件的x、y坐標設為上面得到的中間點坐標
e.開啟屬性動畫
f.當動畫結束時的操作

獲取控件在屏幕中的絕對坐標:

int[] parentLocation = new int[2];
mRLayout.getLocationInWindow(parentLocation);

計算開始坐標和結束坐標:

//開始掉落的商品的起始點:商品起始點-父布局起始點+該商品圖片的一半
float startX = startLoc[0] - parentLocation[0] + iv.getWidth() / 2;
float startY = startLoc[1] - parentLocation[1] + iv.getHeight() / 2;

//商品掉落后的終點坐標:購物車起始點-父布局起始點+購物車圖片的1/5
float toX = endLoc[0] - parentLocation[0] + mCart.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(1000);
? ? ? ? // 勻速線性插值器
? ? ? ? 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) {
? ? ? ? ? ? ? ? // 購物車的數量加1
? ? ? ? ? ? ? ? i++;
? ? ? ? ? ? ? ? mCount.setText(String.valueOf(i));
? ? ? ? ? ? ? ? // 把移動的圖片imageView從父布局里移除
? ? ? ? ? ? ? ? mRLayout.removeView(goods);
? ? ? ? ? ? }

? ? ? ? ? ? @Override
? ? ? ? ? ? public void onAnimationCancel(Animator animation) {

? ? ? ? ? ? }

? ? ? ? ? ? @Override
? ? ? ? ? ? public void onAnimationRepeat(Animator animation) {

? ? ? ? ? ? }
? ? ? ? });

xml里的寫法:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
? ? xmlns:android="http://schemas.android.com/apk/res/android"
? ? android:layout_width="match_parent"
? ? android:layout_height="match_parent"
? ? android:orientation="vertical"
? ? >
? ? <RelativeLayout
? ? ? ? ? ? android:id="@+id/rl"
? ? ? ? ? ? android:layout_width="match_parent"
? ? ? ? ? ? android:layout_height="wrap_content">
? ? ? ? ? ? <Button
? ? ? ? ? ? ? ? android:id="@+id/add"
? ? ? ? ? ? ? ? android:layout_width="wrap_content"
? ? ? ? ? ? ? ? android:layout_height="wrap_content"
? ? ? ? ? ? ? ? android:text="加入購物車"/>
? ? ? ? ? ? <ImageView
? ? ? ? ? ? ? ? android:layout_toRightOf="@id/add"
? ? ? ? ? ? ? ? android:id="@+id/goods"
? ? ? ? ? ? ? ? android:src="@mipmap/ic_launcher"
? ? ? ? ? ? ? ? android:layout_width="50dp"
? ? ? ? ? ? ? ? android:layout_height="50dp"
? ? ? ? ? ? ? ? />
? ? ? ? ? ? <TextView
? ? ? ? ? ? ? ? android:id="@+id/count"
? ? ? ? ? ? ? ? android:layout_marginLeft="300dp"
? ? ? ? ? ? ? ? android:layout_marginTop="70dp"
? ? ? ? ? ? ? ? android:layout_width="wrap_content"
? ? ? ? ? ? ? ? android:layout_height="wrap_content"
? ? ? ? ? ? ? ? android:text="0"/>

? ? ? ? ? ? <ImageView
? ? ? ? ? ? ? ? android:id="@+id/cart"
? ? ? ? ? ? ? ? android:layout_width="60dp"
? ? ? ? ? ? ? ? android:layout_height="60dp"
? ? ? ? ? ? ? ? android:layout_marginLeft="300dp"
? ? ? ? ? ? ? ? android:layout_marginTop="240dp"
? ? ? ? ? ? ? ? android:src="@drawable/ic_shopping_cart"
? ? ? ? ? ? ? ? />
? ? ? ? </RelativeLayout>

</LinearLayout>

使用了Butterknife和自己封裝的BaseActivity,要使用的話需要自行修改代碼。

完整代碼:

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.xp.baseapp.R;
import com.xp.baseapp.base.BaseActivity;

import butterknife.BindView;
import butterknife.OnClick;

public class ShoppingCartAnimationActivity extends BaseActivity {

? ? @BindView(R.id.add)
? ? Button mAdd;
? ? @BindView(R.id.rl)
? ? RelativeLayout mRLayout;
? ? @BindView(R.id.count)
? ? TextView mCount;
? ? @BindView(R.id.cart)
? ? ImageView mCart;
? ? @BindView(R.id.goods)
? ? ImageView mGoods;
? ? private PathMeasure mPathMeasure;
? ? /**
? ? ?* 貝塞爾曲線中間過程的點的坐標
? ? ?*/
? ? private float[] mCurrentPosition = new float[2];
? ? /**
? ? ?* 購物車中的商品數量
? ? ?*/
? ? private int i = 0;

? ? @Override
? ? protected int getContentViewId() {
? ? ? ? return R.layout.activity_shopping_cart_animation;
? ? }

? ? @Override
? ? protected void init() {

? ? }

? ? @OnClick(R.id.add)
? ? public void addGood(View v) {
? ? ? ? addCart(mGoods);
? ? }

? ? /**
? ? ?* 把商品添加到購物車的動畫效果
? ? ?*
? ? ?* @param iv
? ? ?*/
? ? private void addCart(ImageView iv) {
// ? ? ?一、創造出執行動畫的主題---imageview
? ? ? ? //代碼new一個imageview,圖片資源是上面的imageview的圖片
? ? ? ? // (這個圖片就是執行動畫的圖片,從開始位置出發,經過一個拋物線(貝塞爾曲線),移動到購物車里)
? ? ? ? final ImageView goods = new ImageView(ShoppingCartAnimationActivity.this);
? ? ? ? goods.setImageDrawable(iv.getDrawable());
? ? ? ? RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(100, 100);
? ? ? ? mRLayout.addView(goods, params);

// ? ? ? ?二、計算動畫開始/結束點的坐標的準備工作
? ? ? ? //得到父布局的起始點坐標(用于輔助計算動畫開始/結束時的點的坐標)
? ? ? ? int[] parentLocation = new int[2];
? ? ? ? mRLayout.getLocationInWindow(parentLocation);

? ? ? ? //得到商品圖片的坐標(用于計算動畫開始的坐標)
? ? ? ? int startLoc[] = new int[2];
? ? ? ? iv.getLocationInWindow(startLoc);

? ? ? ? //得到購物車圖片的坐標(用于計算動畫結束后的坐標)
? ? ? ? int endLoc[] = new int[2];
? ? ? ? mCart.getLocationInWindow(endLoc);


// ? ? ? ?三、正式開始計算動畫開始/結束的坐標
? ? ? ? //開始掉落的商品的起始點:商品起始點-父布局起始點+該商品圖片的一半
? ? ? ? float startX = startLoc[0] - parentLocation[0] + iv.getWidth() / 2;
? ? ? ? float startY = startLoc[1] - parentLocation[1] + iv.getHeight() / 2;

? ? ? ? //商品掉落后的終點坐標:購物車起始點-父布局起始點+購物車圖片的1/5
? ? ? ? float toX = endLoc[0] - parentLocation[0] + mCart.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(1000);
? ? ? ? // 勻速線性插值器
? ? ? ? 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) {
? ? ? ? ? ? ? ? // 購物車的數量加1
? ? ? ? ? ? ? ? i++;
? ? ? ? ? ? ? ? mCount.setText(String.valueOf(i));
? ? ? ? ? ? ? ? // 把移動的圖片imageView從父布局里移除
? ? ? ? ? ? ? ? mRLayout.removeView(goods);
? ? ? ? ? ? }

? ? ? ? ? ? @Override
? ? ? ? ? ? public void onAnimationCancel(Animator animation) {

? ? ? ? ? ? }

? ? ? ? ? ? @Override
? ? ? ? ? ? public void onAnimationRepeat(Animator animation) {

? ? ? ? ? ? }
? ? ? ? });
? ? }
}

原文鏈接:https://blog.csdn.net/SilenceOO/article/details/73499149

欄目分類
最近更新