Android 屬性動畫初戰,經過屬性動畫實現相似於美團外賣購物車消失顯示的動效。git
什麼是屬性動畫?屬性動畫能夠經過直接更改 View 的屬性來實現 View 動畫。例如:github
因而可知,利用屬性動畫幾乎能夠處理任何的涉及到 View 的動畫效果。app
實戰具體的細節就很少說了,網上相應的教程也很多。這篇博客主要是來實現相似於美團外賣購物車的效果。ide
首先分析購物車動畫具體的細節:在滑動過程當中,「購物車」向右移動,直至一半隱藏到右側;在手指停留在屏幕中時,「購物車」還隱藏在右側;當手指離開屏幕,「購物車」在必定時間後從新移動回來。函數
以上的動畫細節能夠分析出和 RecycleView 的滾動事件息息相關,所以動畫就應該在 RecycleView 的滾動事件中實現。佈局
上圖的藍色圖片既是咱們要處理的 View 。動畫
接下來給 RecycleView 加上滾動事件,滑動或者飛翔時圖片消失,當中止滑動時圖片顯示。this
1 // 給rv加上滾動事件 2 rv.addOnScrollListener(new RecyclerView.OnScrollListener() { 3 @Override 4 public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { 5 switch (newState) { 6 case RecyclerView.SCROLL_STATE_DRAGGING:// 滾動中 7 case RecyclerView.SCROLL_STATE_SETTLING:// 飛翔中 8 iv.setVisibility(View.GONE); 9 break;10 case RecyclerView.SCROLL_STATE_IDLE:// 中止滾動11 iv.setVisibility(View.VISIBLE);12 break;13 }14 }15 });
效果圖:3d
根據上面的圖能夠發現觸發時機基本是沒問題了,接下來要作的是讓消失不突兀,加上消失的動畫。調試
消失的實質是 View 的 x 座標從當前位置一直往右直到變爲隱藏了一半,下面讓咱們來實現這個效果:
1 // 消失動畫的基本屬性(從iv當前的x座標一直到出了屏幕右側一半) 2 disappearAnimator = ValueAnimator.ofFloat(iv.getX(), (float) (Utils.getScreenWidth(this) - iv.getWidth() / 2.0)); 3 disappearAnimator.setDuration(400);// 動畫持續時間 4 disappearAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 5 @Override 6 public void onAnimationUpdate(ValueAnimator animation) {// Value更新事件 7 float curValue = (float) animation.getAnimatedValue(); 8 iv.setX(curValue); 9 }10 });11 12 // 給rv加上滾動事件13 rv.addOnScrollListener(new RecyclerView.OnScrollListener() {14 @Override15 public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {16 switch (newState) {17 case RecyclerView.SCROLL_STATE_DRAGGING:// 滾動中18 case RecyclerView.SCROLL_STATE_SETTLING:// 飛翔中19 disappearAnimator.start();20 break;21 case RecyclerView.SCROLL_STATE_IDLE:// 中止滾動22 iv.setVisibility(View.VISIBLE);23 break;24 }25 }26 });
然而發現實際上動畫是這樣的:
發現他是從最左邊一直移動到了最右邊,與咱們的需求不符。
經調試發現,在 onCreate 的時候 iv 還沒有初始化完畢,所以寬高以及座標都還不能獲取到。因此獲取到的座標以及寬度都是0。
因此能夠在滾動事件中獲取 iv 的座標以及寬高,更改後的代碼以下:
1 // 給rv加上滾動事件 2 rv.addOnScrollListener(new RecyclerView.OnScrollListener() { 3 @Override 4 public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { 5 // 獲取iv的座標以及寬高 6 if (0 == originX) { 7 originX = iv.getX(); 8 ivWidth = iv.getWidth(); 9 }10 11 switch (newState) {12 case RecyclerView.SCROLL_STATE_DRAGGING:// 滾動中13 case RecyclerView.SCROLL_STATE_SETTLING:// 飛翔中14 // 消失動畫的基本屬性(從iv當前的x座標一直到出了屏幕右側一半)15 if (disappearAnimator == null) {16 disappearAnimator = ValueAnimator.ofFloat(originX, (float) (screenWidth - ivWidth / 2.0));17 disappearAnimator.setDuration(400);// 動畫持續時間18 disappearAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {19 @Override20 public void onAnimationUpdate(ValueAnimator animation) {// Value更新事件21 float curValue = (float) animation.getAnimatedValue();22 iv.setX(curValue);23 }24 });25 }26 27 disappearAnimator.start();28 break;29 case RecyclerView.SCROLL_STATE_IDLE:// 中止滾動30 iv.setVisibility(View.VISIBLE);31 break;32 }33 }34 });
效果以下圖:
既然已經實現了消失的動畫,那出現的動畫也就不難了。出現的實質是 View 的 x 座標從右側一半一直運動到原始位置。
1 case RecyclerView.SCROLL_STATE_IDLE:// 中止滾動 2 // 出現動畫的基本屬性(從屏幕右側一半到原始位置) 3 if (appearAnimator == null) { 4 appearAnimator = ValueAnimator.ofFloat((float) (screenWidth - ivWidth / 2.0), originX); 5 appearAnimator.setDuration(400);// 動畫持續時間 6 appearAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 7 @Override 8 public void onAnimationUpdate(ValueAnimator animation) {// Value更新事件 9 float curValue = (float) animation.getAnimatedValue();10 iv.setX(curValue);11 }12 });13 }14 15 appearAnimator.start();16 break;
效果圖以下:
可是發現若是頻繁的滑動暫停的話動畫會衝突,所以須要作一些斷定,若是動畫正在運行則再也不從新開始動畫。改動後的代碼以下:
1 switch (newState) { 2 case RecyclerView.SCROLL_STATE_DRAGGING:// 滾動中 3 case RecyclerView.SCROLL_STATE_SETTLING:// 飛翔中 4 // 消失動畫的基本屬性(從iv當前的x座標一直到出了屏幕右側一半) 5 if (disappearAnimator == null) { 6 disappearAnimator = ValueAnimator.ofFloat(originX, (float) (screenWidth - ivWidth / 2.0)); 7 disappearAnimator.setDuration(400);// 動畫持續時間 8 disappearAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 9 @Override10 public void onAnimationUpdate(ValueAnimator animation) {// Value更新事件11 float curValue = (float) animation.getAnimatedValue();12 iv.setX(curValue);13 }14 });15 }16 17 // 若是消失動畫還未開始執行而且iv的位置在原始位置,則執行18 if (!disappearAnimator.isStarted() && originX == iv.getX()) {19 disappearAnimator.start();20 }21 break;22 case RecyclerView.SCROLL_STATE_IDLE:// 中止滾動23 // 出現動畫的基本屬性(從屏幕右側一半到原始位置)24 if (appearAnimator == null) {25 appearAnimator = ValueAnimator.ofFloat((float) (screenWidth - ivWidth / 2.0), originX);26 appearAnimator.setDuration(400);// 動畫持續時間27 appearAnimator.setStartDelay(700);// 延遲時間28 appearAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {29 @Override30 public void onAnimationUpdate(ValueAnimator animation) {// Value更新事件31 float curValue = (float) animation.getAnimatedValue();32 iv.setX(curValue);33 }34 });35 }36 37 // 若是出現動畫還未開始執行,則執行38 if (!appearAnimator.isStarted()) {39 appearAnimator.start();40 }41 break;42 }
可是發現仍是會有衝突,經檢測,發現是出現動畫和消失動畫互相干擾的緣故。當滑動已暫停但出現動畫還未執行完畢,此時從新滑動會觸發消失動畫。
所以須要給出現動畫加一個延遲,而且若是處於非暫停狀態須要取消出現動畫。(也許美團外賣暫停一段時間纔開始出現的緣由就是防止用戶不停的滑動暫停吧。)
修改後的代碼以下:
case RecyclerView.SCROLL_STATE_DRAGGING:// 滾動中case RecyclerView.SCROLL_STATE_SETTLING:// 飛翔中 // 消失動畫的基本屬性(從iv當前的x座標一直到出了屏幕右側一半) if (disappearAnimator == null) { disappearAnimator = ValueAnimator.ofFloat(originX, (float) (screenWidth - ivWidth / 2.0)); disappearAnimator.setDuration(400);// 動畫持續時間 disappearAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) {// Value更新事件 float curValue = (float) animation.getAnimatedValue(); iv.setX(curValue); } }); } // 若是此時出現動畫已開始,則取消 if (appearAnimator != null && appearAnimator.isStarted()) { appearAnimator.cancel(); } // 若是消失動畫還未開始執行而且iv的位置在原始位置,則執行 if (!disappearAnimator.isStarted() && originX == iv.getX()) { disappearAnimator.start(); } break;
最終效果如圖所示:
總結
你們若是有什麼疑問或者建議能夠經過評論或者郵件的方式聯繫我,歡迎你們的評論~