Android真正仿攜程首頁view實現
阿新 • • 發佈:2019-02-18
package com.example.asiatravel.ctriphomescaleview.view; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.animation.LinearInterpolator; import android.widget.ImageView; /** * Created by kuangxiaoguo on 16/8/30. */ public class CTripHomeScaleView extends ImageView { /** * 動畫持續時長 */ private static final int DURATION = 100; /** * 快速點選的時間間隔 */ private static final int TIME_DELAY = 500; /** * 滑動最小距離 */ private static final int MIN_MOVE_DPI = 10; /** * 縮放的scale */ private static final float SMALL_SCALE = 0.95f; /** * 初始scale */ private static final float ONE_SCALE = 1f; /** * 判斷縮小動畫有沒有執行過 */ private boolean hasDoneAnimation; /** * 點選事件監聽 */ private OnClickListener listener; /** * 開始動畫 */ private AnimatorSet beginAnimatorSet; /** * scale返回動畫 */ private AnimatorSet backAnimatorSet; private int downX; private int downY; private long lastClickTime; public CTripHomeScaleView(Context context) { this(context, null); } public CTripHomeScaleView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CTripHomeScaleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initAnimation(); } /** * Init scale animation */ private void initAnimation() { ObjectAnimator beginXAnimation = ObjectAnimator.ofFloat(this, "scaleX", ONE_SCALE, SMALL_SCALE).setDuration(DURATION); beginXAnimation.setInterpolator(new LinearInterpolator()); ObjectAnimator beginYAnimation = ObjectAnimator.ofFloat(this, "scaleY", ONE_SCALE, SMALL_SCALE).setDuration(DURATION); beginYAnimation.setInterpolator(new LinearInterpolator()); ObjectAnimator backXAnimation = ObjectAnimator.ofFloat(this, "scaleX", SMALL_SCALE, ONE_SCALE).setDuration(DURATION); backXAnimation.setInterpolator(new LinearInterpolator()); ObjectAnimator backYAnimation = ObjectAnimator.ofFloat(this, "scaleY", SMALL_SCALE, ONE_SCALE).setDuration(DURATION); backYAnimation.setInterpolator(new LinearInterpolator()); beginAnimatorSet = new AnimatorSet(); beginAnimatorSet.play(beginXAnimation).with(beginYAnimation); backAnimatorSet = new AnimatorSet(); backAnimatorSet.play(backXAnimation).with(backYAnimation); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: /** * 判斷是不是快速點選 */ if (isFastClick()) { return true; } /** * 請求父類不要攔截我的事件,意思是讓我來處理接下來的滑動或別的事件 */ getParent().requestDisallowInterceptTouchEvent(true); downX = (int) event.getX(); downY = (int) event.getY(); hasDoneAnimation = false; post(new Runnable() { @Override public void run() { beginAnimatorSet.start(); } }); break; case MotionEvent.ACTION_MOVE: int moveX = (int) event.getX(); int moveY = (int) event.getY(); int moveDistanceX = Math.abs(moveX) - downX; int moveDistanceY = Math.abs(moveY) - downY; /** * 這裡是判斷是向左還是向右滑動,然後用view的寬度計算出一個距離compareWidth,當滑動距離超出compareWidth時,需要執行返回動畫. */ int compareWidth = moveDistanceX > 0 ? getWidth() - downX : downX; /** * 第一個條件:判斷向上或向下滑動距離大於滑動最小距離 * 第二個條件:判斷向左或向右的滑動距離是否超出(compareWidth-最小距離) * 第三個條件:判斷有沒有執行過返回動畫並在執行過一次後置為true. */ if ((Math.abs(moveDistanceY) > dip2px(MIN_MOVE_DPI) || Math.abs(moveDistanceX) >= compareWidth - dip2px(MIN_MOVE_DPI)) && !hasDoneAnimation) { /** * 一 只要滿足上述條件,就代表使用者不是點選view,而是執行了滑動操作,這個時候我們就需要父類以及我們的最上層的控制元件來 * 攔截我們的事件,讓最外層控制元件處理接下來的事件,比如scrollview的滑動. * 二 因為我們執行了滑動操作,所以要執行view的返回動畫 */ getParent().requestDisallowInterceptTouchEvent(false); hasDoneAnimation = true; post(new Runnable() { @Override public void run() { backAnimatorSet.start(); } }); } break; case MotionEvent.ACTION_UP: /** * 這裡如果我們是單純的點選事件就會執行 */ if (!hasDoneAnimation) { hasDoneAnimation = true; post(new Runnable() { @Override public void run() { backAnimatorSet.start(); } }); post(new Runnable() { @Override public void run() { /** * 介面回撥點選事件 */ if (listener != null) { listener.onClick(CTripHomeScaleView.this); } } }); } break; } return true; } public void setOnClickListener(OnClickListener l) { listener = l; } public interface OnClickListener { void onClick(View v); } /** * Make dp to px * * @param dipValue dp you need to change * @return Get px according to your dp value. */ public int dip2px(float dipValue) { final float scale = getResources().getDisplayMetrics().density; return (int) (dipValue * scale + 0.5f); } /** * Judge is fast click event. * * @return Is fast click or not. */ public boolean isFastClick() { long time = System.currentTimeMillis(); long timeD = time - lastClickTime; if (timeD < TIME_DELAY) { return true; } else { lastClickTime = time; return false; } } }