加入購物車動畫效果實現
不知道大家有沒有發現,主流的電商類APP新增商品到購物車時,都會伴隨一個小的“新增”動畫。你有沒有想過它是怎麼實現的呢?今天我們就一起來學習下。
其實實現這個效果很簡單,主要涉及到兩個知識點:貝塞爾曲線和自定義Evaluator估值器。下面我先簡單介紹下這兩個知識點,如果你之前有了解過這兩塊的話,可以直接翻到下面看下實現程式碼。
貝塞爾曲線是數值分析領域的重要引數曲線,在我們的生活中隨處都可以看到它的影子,比如:QQ聊天氣泡的拖拽效果、直播室送花點贊效果、電量水波紋效果等等。貝塞爾曲線可以分為一階貝塞爾曲線、二階貝塞爾曲線、三階貝塞爾曲線 .....。在這裡我們用到了二階貝塞爾曲線,下面我們先來看下它的計算公式:
相信大家在開發過程中都有用到過屬性動畫吧,屬性動畫中有兩個很重要的知識點,那就是差值器Interpolator和估值器Evaluator。簡單來講,差值器就類似於我們物理中所學的“加速度”,比如我們的執行動畫需要先加速再減速。Android系統為我們內建了幾種常見的差值器,在某些特定情況下不能滿足需要的話,我們就需要實現TimeInterpolator介面實現自定義差值器。估值器Evaluator其實就是一個轉換器,他能把小數進度轉換成對應的具體數值,我們可以實現TypeEvaluator介面來自定義估值器。
我們先思考一下,加入購物車動畫效果就相當於數學中常見的拋物線,可以藉助二階貝塞爾曲線來實現,那我們怎麼確定起始點P0、控制點P1、終點P2的位置呢?起始點P0的位置就是我們的商品新增按鈕所在位置,終點P2位置就是介面左下角購物車Icon圖示所在的位置,控制點的位置要怎麼選取呢?在這裡我們可以沿新增按鈕水平向左,沿購物車Icon圖示豎直向上,兩條線的交點處正可以作為我們的控制點座標,到此三個點正好構成一個倒立的直角三角形。控制點P1的橫座標等於終點P2的橫座標,控制點P1的縱座標等於起始點P0的縱座標。下面我們就可以進行編碼工作了。
首先自定義估值器CartEvaluator:
public class CartEvaluator implements TypeEvaluator<PointF>{
private PointF pointCur;
private PointF mControlPoint;
public CartEvaluator(PointF mControlPoint) {
this.mControlPoint = mControlPoint;
pointCur = new PointF();
}
@Override
public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
// 將二階貝塞爾曲線的計算公式直接代入即可
pointCur.x = (1 - fraction) * (1 - fraction) * startValue.x
+ 2 * fraction * (1 - fraction) * mControlPoint.x + fraction * fraction * endValue.x;
pointCur.y = (1 - fraction) * (1 - fraction) * startValue.y
+ 2 * fraction * (1 - fraction) * mControlPoint.y + fraction * fraction * endValue.y;
return pointCur;
}
}
在這裡我們建立了一個pointCur物件,專門用來儲存當前移動點的座標。
下面看下Demo中的佈局檔案效果,程式碼就不貼出來了,就是佈局左下角放置了一個購物車圖示,右上角放置了三個新增按鈕,用來模擬新增商品操作:最後看下Activity中的程式碼實現:
public class MainActivity extends AppCompatActivity {
private ImageView mAddOne;
private ImageView mAddTwo;
private ImageView mAddThree;
private ImageView mCart;
private ViewGroup mRootView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initListener();
}
// 初始化控制元件
private void initView(){
mRootView = (ViewGroup) getWindow().getDecorView();
mCart = findViewById(R.id.mCart);
mAddOne = findViewById(R.id.mAddOne);
mAddTwo = findViewById(R.id.mAddTwo);
mAddThree = findViewById(R.id.mAddThree);
}
// 初始化監聽
private void initListener(){
mAddOne.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
playAnim(view);
}
});
mAddTwo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
playAnim(view);
}
});
mAddThree.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
playAnim(view);
}
});
}
// 執行動畫
private void playAnim(final View view){
//建立int陣列,用來接收貝塞爾起始點座標和終點座標值
int[] startPosition = new int[2];
int[] endPosition = new int[2];
view.getLocationInWindow(startPosition);
mCart.getLocationInWindow(endPosition);
PointF startF = new PointF(); //起始點 startF
PointF endF = new PointF(); //終點 endF
PointF controlF = new PointF(); //控制點 controlF
startF.x = startPosition[0];
startF.y = startPosition[1] ;
endF.x = endPosition[0]+mCart.getWidth()/2-view.getWidth()/2; //微調處理,確保動畫執行完畢“新增”圖示中心點與購物車中心點重合
endF.y = endPosition[1]+mCart.getHeight()/2 - view.getHeight()/2;
controlF.x = endF.x;
controlF.y = startF.y;
// 建立執行動畫的“新增”圖示
final ImageView imageView = new ImageView(this);
mRootView.addView(imageView);
imageView.setImageResource(R.mipmap.cartadd);
imageView.getLayoutParams().width = view.getMeasuredWidth();
imageView.getLayoutParams().height = view.getMeasuredHeight();
ValueAnimator valueAnimator = ValueAnimator.ofObject(new CartEvaluator(controlF), startF, endF);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF pointF = (PointF) animation.getAnimatedValue();
imageView.setX(pointF.x);
imageView.setY(pointF.y);
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
// 動畫執行完畢,將執行動畫的“新增”圖示移除掉
mRootView.removeView(imageView);
// 執行購物車縮放動畫
AnimatorSet animatorSet = new AnimatorSet();
ObjectAnimator animatorX = ObjectAnimator.ofFloat(mCart, "scaleX", 1f, 1.2f, 1f);
ObjectAnimator animatorY = ObjectAnimator.ofFloat(mCart, "scaleY", 1f, 1.2f, 1f);
animatorSet.play(animatorX).with(animatorY);
animatorSet.setDuration(400);
animatorSet.start();
}
});
valueAnimator.setDuration(800);
valueAnimator.start();
}
}
程式碼中相關地方都標上註釋了,相信大家都能夠理解,整體程式碼量還是很少的。最後我們看下實現效果:相關文章
- iOS加入購物車動畫效果iOS動畫
- 用Provider實現商品加入購物車的動畫效果IDE動畫
- javascript仿天貓加入購物車動畫效果JavaScript動畫
- Vue實現購物車效果Vue
- 貝塞爾曲線的css實現——淘寶加入購物車基礎動畫CSS動畫
- iOS 購物車動畫iOS動畫
- jQuery 加入購物車 彈窗jQuery
- angularjs實現的購物車效果程式碼例項AngularJS
- 購物車的實現原理
- 購物車原理以及實現
- React實現購物車功能React
- 使用二階貝塞爾曲線實現新增購物車動畫動畫
- 【jquery】實現購物車加減jQuery
- jQuery商品飛入購物車效果jQuery
- 原生js實現購物車結算JS
- Android實現商城購物車功能Android
- vue2.0實現購物車功能Vue
- 二級列表完美實現購物車
- AngularJS 實現簡單購物車AngularJS
- Vue實現簡單的購物車功能Vue
- 使用SSH+session+mysql實現購物車SessionMySql
- 網站購物車介面(div+css實現)網站CSS
- jQuery實現購物車的增刪改查jQuery
- 我的Vue之旅 11 Vuex 實現購物車Vue
- Python Django實現簡單購物車功能PythonDjango
- 購物車的實現及結算處理
- 基於XML的購物車的實現(轉)XML
- asp.net 實現購物車詳細程式碼ASP.NET
- 想請問下關於購物車如何實現
- 購物車模組
- React實現動畫效果React動畫
- Javascript實現動畫效果JavaScript動畫
- JS動畫效果——多物體動畫JS動畫
- 原生JS實現拋物線動畫以及動態模糊效果JS動畫
- 仿餓了麼加入購物車旋轉控制元件 – 自帶閃轉騰挪動畫 的按鈕控制元件動畫
- 仿餓了麼加入購物車旋轉控制元件 - 自帶閃轉騰挪動畫 的按鈕控制元件動畫
- 直播app原始碼,map實現購物車選擇功能APP原始碼
- flutter 購物車功能Flutter