SwipeHelper.java revision 96f4818ef41141649337d4dee09f837594e93d09
107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka/* 207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * Copyright (C) 2011 The Android Open Source Project 307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * 407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * Licensed under the Apache License, Version 2.0 (the "License"); 507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * you may not use this file except in compliance with the License. 607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * You may obtain a copy of the License at 707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * 807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * http://www.apache.org/licenses/LICENSE-2.0 907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * 1007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * Unless required by applicable law or agreed to in writing, software 1107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * distributed under the License is distributed on an "AS IS" BASIS, 1207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * See the License for the specific language governing permissions and 1407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka * limitations under the License. 1507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka */ 1607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 1707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkapackage com.android.systemui; 1807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 1907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.animation.Animator; 2007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.animation.ObjectAnimator; 2107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.animation.Animator.AnimatorListener; 2207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.animation.ValueAnimator; 2307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.animation.ValueAnimator.AnimatorUpdateListener; 2407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.graphics.RectF; 2507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.util.Log; 2607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.view.animation.LinearInterpolator; 2707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.view.MotionEvent; 2807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.view.VelocityTracker; 2907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkaimport android.view.View; 3007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 3107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurkapublic class SwipeHelper { 3207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka static final String TAG = "com.android.systemui.SwipeHelper"; 3396f4818ef41141649337d4dee09f837594e93d09Daniel Sandler private static final boolean DEBUG = false; 3407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private static final boolean DEBUG_INVALIDATE = false; 3507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private static final boolean SLOW_ANIMATIONS = false; // DEBUG; 3607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 3707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public static final int X = 0; 3807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public static final int Y = 1; 3907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 4007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private boolean CONSTRAIN_SWIPE = true; 4107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private boolean FADE_OUT_DURING_SWIPE = true; 4207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private boolean DISMISS_IF_SWIPED_FAR_ENOUGH = true; 4307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 4407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec 4507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private int MAX_ESCAPE_ANIMATION_DURATION = 500; // ms 460761e4cd95b6968dd4b1659a766ef504d13f6d50Daniel Sandler private int MAX_DISMISS_VELOCITY = 1000; // dp/sec 4707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 250; // ms 4807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 4907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public static float ALPHA_FADE_START = 0.8f; // fraction of thumbnail width 5007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka // where fade starts 5107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka static final float ALPHA_FADE_END = 0.5f; // fraction of thumbnail width 5207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka // beyond which alpha->0 5307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 5407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private float mPagingTouchSlop; 5507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private Callback mCallback; 5607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private int mSwipeDirection; 5707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private VelocityTracker mVelocityTracker; 5807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 5907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private float mInitialTouchPos; 6007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private boolean mDragging; 6107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private View mCurrView; 6207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private float mDensityScale; 6307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 6407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public SwipeHelper(int swipeDirection, Callback callback, float densityScale, 6507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float pagingTouchSlop) { 6607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mCallback = callback; 6707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mSwipeDirection = swipeDirection; 6807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mVelocityTracker = VelocityTracker.obtain(); 6907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mDensityScale = densityScale; 7007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mPagingTouchSlop = pagingTouchSlop; 7107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 7207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 7307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void setDensityScale(float densityScale) { 7407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mDensityScale = densityScale; 7507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 7607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 7707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void setPagingTouchSlop(float pagingTouchSlop) { 7807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mPagingTouchSlop = pagingTouchSlop; 7907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 8007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 8107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private float getPos(MotionEvent ev) { 8207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return mSwipeDirection == X ? ev.getX() : ev.getY(); 8307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 8407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 8507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private float getPos(View v) { 8607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return mSwipeDirection == X ? v.getX() : v.getY(); 8707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 8807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 8907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private float getVelocity(VelocityTracker vt) { 9007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return mSwipeDirection == X ? vt.getXVelocity() : 9107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka vt.getYVelocity(); 9207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 9307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 9407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private ObjectAnimator createTranslationAnimation(View v, float newPos) { 9507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka ObjectAnimator anim = ObjectAnimator.ofFloat(v, 9607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mSwipeDirection == X ? "translationX" : "translationY", newPos); 9707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return anim; 9807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 9907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 10007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private float getPerpendicularVelocity(VelocityTracker vt) { 10107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return mSwipeDirection == X ? vt.getYVelocity() : 10207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka vt.getXVelocity(); 10307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 10407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 10507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private void setTranslation(View v, float translate) { 10607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (mSwipeDirection == X) { 10707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka v.setTranslationX(translate); 10807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } else { 10907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka v.setTranslationY(translate); 11007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 11107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 11207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 11307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private float getSize(View v) { 11407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return mSwipeDirection == X ? v.getMeasuredWidth() : 11507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka v.getMeasuredHeight(); 11607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 11707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 11807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private float getContentSize(View v) { 11907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka View content = mCallback.getChildContentView(v); 12007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return getSize(content); 12107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 12207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 12307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka private float getAlphaForOffset(View view, float thumbSize) { 12407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka final float fadeSize = ALPHA_FADE_END * thumbSize; 12507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float result = 1.0f; 12607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float pos = getPos(view); 12707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (pos >= thumbSize * ALPHA_FADE_START) { 12807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka result = 1.0f - (pos - thumbSize * ALPHA_FADE_START) / fadeSize; 12907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } else if (pos < thumbSize * (1.0f - ALPHA_FADE_START)) { 13007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka result = 1.0f + (thumbSize * ALPHA_FADE_START + pos) / fadeSize; 13107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 13207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return result; 13307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 13407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 135a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler // invalidate the view's own bounds all the way up the view hierarchy 136a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler public static void invalidateGlobalRegion(View view) { 137a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler invalidateGlobalRegion( 138a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler view, 139a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom())); 140a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler } 141a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler 142a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler // invalidate a rectangle relative to the view's coordinate system all the way up the view 143a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler // hierarchy 144a375c94fca986d76d21f8cb9a3eb29f1ef88c4a8Daniel Sandler public static void invalidateGlobalRegion(View view, RectF childBounds) { 14596f4818ef41141649337d4dee09f837594e93d09Daniel Sandler //childBounds.offset(view.getTranslationX(), view.getTranslationY()); 14607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (DEBUG_INVALIDATE) 14707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka Log.v(TAG, "-------------"); 14807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka while (view.getParent() != null && view.getParent() instanceof View) { 14907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka view = (View) view.getParent(); 15007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka view.getMatrix().mapRect(childBounds); 15107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka view.invalidate((int) Math.floor(childBounds.left), 15207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka (int) Math.floor(childBounds.top), 15307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka (int) Math.ceil(childBounds.right), 15407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka (int) Math.ceil(childBounds.bottom)); 15507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (DEBUG_INVALIDATE) { 15607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka Log.v(TAG, "INVALIDATE(" + (int) Math.floor(childBounds.left) 15707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka + "," + (int) Math.floor(childBounds.top) 15807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka + "," + (int) Math.ceil(childBounds.right) 15907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka + "," + (int) Math.ceil(childBounds.bottom)); 16007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 16107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 16207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 16307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 16407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public boolean onInterceptTouchEvent(MotionEvent ev) { 16507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka final int action = ev.getAction(); 16607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 16707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka switch (action) { 16807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka case MotionEvent.ACTION_DOWN: 16907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mDragging = false; 17007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mCurrView = mCallback.getChildAtPosition(ev); 17107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mVelocityTracker.clear(); 17207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mVelocityTracker.addMovement(ev); 17307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mInitialTouchPos = getPos(ev); 17407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka break; 17507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka case MotionEvent.ACTION_MOVE: 17607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (mCurrView != null) { 17707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mVelocityTracker.addMovement(ev); 17807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float pos = getPos(ev); 17907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float delta = pos - mInitialTouchPos; 18007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (Math.abs(delta) > mPagingTouchSlop) { 18107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mCallback.onBeginDrag(mCurrView); 18207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mDragging = true; 18307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mInitialTouchPos = getPos(ev) - getPos(mCurrView); 18407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 18507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 18607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka break; 18707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka case MotionEvent.ACTION_UP: 18807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mDragging = false; 18907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mCurrView = null; 19007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka break; 19107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 19207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return mDragging; 19307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 19407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 19507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void dismissChild(final View animView, float velocity) { 19607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float newPos; 19707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (velocity < 0 || (velocity == 0 && getPos(animView) < 0)) { 19807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka newPos = -getSize(animView); 19907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } else { 20007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka newPos = getSize(animView); 20107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 20207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka int duration = MAX_ESCAPE_ANIMATION_DURATION; 20307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (velocity != 0) { 20407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka duration = Math.min(duration, 20507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka (int) (Math.abs(newPos - getPos(animView)) * 1000f / Math 20607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka .abs(velocity))); 20707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 20807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka ObjectAnimator anim = createTranslationAnimation(animView, newPos); 20907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka anim.setInterpolator(new LinearInterpolator()); 21007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka anim.setDuration(duration); 21107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka anim.addListener(new AnimatorListener() { 21207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void onAnimationStart(Animator animation) { 21307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 21407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 21507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void onAnimationRepeat(Animator animation) { 21607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 21707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 21807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void onAnimationEnd(Animator animation) { 21907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mCallback.onChildDismissed(animView); 22007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 22107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 22207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void onAnimationCancel(Animator animation) { 22307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mCallback.onChildDismissed(animView); 22407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 22507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka }); 22607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka anim.addUpdateListener(new AnimatorUpdateListener() { 22707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void onAnimationUpdate(ValueAnimator animation) { 22807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (FADE_OUT_DURING_SWIPE) { 22907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka animView.setAlpha(getAlphaForOffset(animView, getContentSize(animView))); 23007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 23107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka invalidateGlobalRegion(animView); 23207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 23307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka }); 23407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka anim.start(); 23507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 23607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 23707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void snapChild(final View animView, float velocity) { 23807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka ObjectAnimator anim = createTranslationAnimation(animView, 0); 23907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka int duration = SNAP_ANIM_LEN; 24007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka anim.setDuration(duration); 24107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka anim.addUpdateListener(new AnimatorUpdateListener() { 24207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public void onAnimationUpdate(ValueAnimator animation) { 24307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (FADE_OUT_DURING_SWIPE) { 24407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka animView.setAlpha(getAlphaForOffset(animView, getContentSize(animView))); 24507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 24607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka invalidateGlobalRegion(animView); 24707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 24807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka }); 24907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka anim.start(); 25007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 25107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 25207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public boolean onTouchEvent(MotionEvent ev) { 25307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (!mDragging) { 25407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return false; 25507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 25607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 25707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mVelocityTracker.addMovement(ev); 25807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka final int action = ev.getAction(); 25907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka switch (action) { 26007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka case MotionEvent.ACTION_OUTSIDE: 26107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka case MotionEvent.ACTION_MOVE: 26207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (mCurrView != null) { 26307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float delta = getPos(ev) - mInitialTouchPos; 26407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka // don't let items that can't be dismissed be dragged more than 26507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka // maxScrollDistance 26607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissed(mCurrView)) { 26707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float size = getSize(mCurrView); 26807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float maxScrollDistance = 0.15f * size; 26907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (Math.abs(delta) >= size) { 27007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka delta = delta > 0 ? maxScrollDistance : -maxScrollDistance; 27107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } else { 27207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka delta = maxScrollDistance * (float) Math.sin((delta/size)*(Math.PI/2)); 27307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 27407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 27507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka setTranslation(mCurrView, delta); 27607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (FADE_OUT_DURING_SWIPE) { 27707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mCurrView.setAlpha(getAlphaForOffset(mCurrView, getContentSize(mCurrView))); 27807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 27907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka invalidateGlobalRegion(mCurrView); 28007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 28107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka break; 28207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka case MotionEvent.ACTION_UP: 28307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka case MotionEvent.ACTION_CANCEL: 28407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (mCurrView != null) { 2850761e4cd95b6968dd4b1659a766ef504d13f6d50Daniel Sandler float maxVelocity = MAX_DISMISS_VELOCITY * mDensityScale; 28607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka mVelocityTracker.computeCurrentVelocity(1000 /* px/sec */, maxVelocity); 28707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float escapeVelocity = SWIPE_ESCAPE_VELOCITY * mDensityScale; 28807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float velocity = getVelocity(mVelocityTracker); 28907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka float perpendicularVelocity = getPerpendicularVelocity(mVelocityTracker); 29007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 29107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka // Decide whether to dismiss the current view 29207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka boolean childSwipedFarEnough = DISMISS_IF_SWIPED_FAR_ENOUGH && 29307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka Math.abs(getPos(mCurrView)) > 0.4 * getSize(mCurrView); 29407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka boolean childSwipedFastEnough = (Math.abs(velocity) > escapeVelocity) && 29507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka (Math.abs(velocity) > Math.abs(perpendicularVelocity)) && 29607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka (velocity > 0) == (getPos(mCurrView) > 0); 29707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 29807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka boolean dismissChild = mCallback.canChildBeDismissed(mCurrView) && 29907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka (childSwipedFastEnough || childSwipedFarEnough); 30007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 30107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka if (dismissChild) { 30207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka // flingadingy 30307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka dismissChild(mCurrView, childSwipedFastEnough ? velocity : 0f); 30407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } else { 30507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka // snappity 30607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka snapChild(mCurrView, velocity); 30707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 30807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 30907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka break; 31007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 31107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka return true; 31207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 31307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 31407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka public interface Callback { 31507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka View getChildAtPosition(MotionEvent ev); 31607d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 31707d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka View getChildContentView(View v); 31807d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 31907d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka boolean canChildBeDismissed(View v); 32007d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 32107d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka void onBeginDrag(View v); 32207d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka 32307d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka void onChildDismissed(View v); 32407d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka } 32507d4046ea914c999b7aaa587b7bfe81d548121f7Michael Jurka} 326