diff options
Diffstat (limited to 'mobile/android/base/java/org/mozilla/gecko/widget/SwipeDismissListViewTouchListener.java')
-rw-r--r-- | mobile/android/base/java/org/mozilla/gecko/widget/SwipeDismissListViewTouchListener.java | 356 |
1 files changed, 0 insertions, 356 deletions
diff --git a/mobile/android/base/java/org/mozilla/gecko/widget/SwipeDismissListViewTouchListener.java b/mobile/android/base/java/org/mozilla/gecko/widget/SwipeDismissListViewTouchListener.java deleted file mode 100644 index 8267fe8a3..000000000 --- a/mobile/android/base/java/org/mozilla/gecko/widget/SwipeDismissListViewTouchListener.java +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Copyright 2012 Roman Nurik - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.mozilla.gecko.widget; - -import android.graphics.Rect; -import android.view.MotionEvent; -import android.view.VelocityTracker; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewGroup; -import android.widget.AbsListView; -import android.widget.AbsListView.RecyclerListener; -import android.widget.ListView; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; -import android.view.ViewPropertyAnimator; - -import org.mozilla.gecko.R; - -/** - * This code is based off of Jake Wharton's NOA port (https://github.com/JakeWharton/SwipeToDismissNOA) - * of Roman Nurik's SwipeToDismiss library. It has been modified for better support with async - * adapters. - * - * A {@link android.view.View.OnTouchListener} that makes the list items in a {@link ListView} - * dismissable. {@link ListView} is given special treatment because by default it handles touches - * for its list items... i.e. it's in charge of drawing the pressed state (the list selector), - * handling list item clicks, etc. - * - * <p>After creating the listener, the caller should also call - * {@link ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener)}, passing - * in the scroll listener returned by {@link #makeScrollListener()}. If a scroll listener is - * already assigned, the caller should still pass scroll changes through to this listener. This will - * ensure that this {@link SwipeDismissListViewTouchListener} is paused during list view - * scrolling.</p> - * - * <p>Example usage:</p> - * - * <pre> - * SwipeDismissListViewTouchListener touchListener = - * new SwipeDismissListViewTouchListener( - * listView, - * new SwipeDismissListViewTouchListener.OnDismissCallback() { - * public void onDismiss(ListView listView, int[] reverseSortedPositions) { - * for (int position : reverseSortedPositions) { - * adapter.remove(adapter.getItem(position)); - * } - * adapter.notifyDataSetChanged(); - * } - * }); - * listView.setOnTouchListener(touchListener); - * listView.setOnScrollListener(touchListener.makeScrollListener()); - * </pre> - * - * <p>For a generalized {@link android.view.View.OnTouchListener} that makes any view dismissable, - * see {@link SwipeDismissTouchListener}.</p> - * - * @see SwipeDismissTouchListener - */ -public class SwipeDismissListViewTouchListener implements View.OnTouchListener { - // Cached ViewConfiguration and system-wide constant values - private final int mSlop; - private final int mMinFlingVelocity; - private final int mMaxFlingVelocity; - private final long mAnimationTime; - - // Fixed properties - private final ListView mListView; - private final OnDismissCallback mCallback; - private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero - - // Transient properties - private float mDownX; - private boolean mSwiping; - private VelocityTracker mVelocityTracker; - private int mDownPosition; - private View mDownView; - private boolean mPaused; - private boolean mDismissing; - - /** - * The callback interface used by {@link SwipeDismissListViewTouchListener} to inform its client - * about a successful dismissal of a list item. - */ - public interface OnDismissCallback { - /** - * Called when the user has indicated they she would like to dismiss one or more list item - * positions. - * - * @param listView The originating {@link ListView}. - * @param position The position being dismissed. - */ - void onDismiss(ListView listView, int position); - } - - /** - * Constructs a new swipe-to-dismiss touch listener for the given list view. - * - * @param listView The list view whose items should be dismissable. - * @param callback The callback to trigger when the user has indicated that she would like to - * dismiss one or more list items. - */ - public SwipeDismissListViewTouchListener(ListView listView, OnDismissCallback callback) { - ViewConfiguration vc = ViewConfiguration.get(listView.getContext()); - mSlop = vc.getScaledTouchSlop(); - mMinFlingVelocity = vc.getScaledMinimumFlingVelocity(); - mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity(); - mAnimationTime = listView.getContext().getResources().getInteger( - android.R.integer.config_shortAnimTime); - mListView = listView; - mCallback = callback; - } - - /** - * Enables or disables (pauses or resumes) watching for swipe-to-dismiss gestures. - * - * @param enabled Whether or not to watch for gestures. - */ - public void setEnabled(boolean enabled) { - mPaused = !enabled; - } - - /** - * Returns an {@link android.widget.AbsListView.OnScrollListener} to be added to the - * {@link ListView} using - * {@link ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener)}. - * If a scroll listener is already assigned, the caller should still pass scroll changes - * through to this listener. This will ensure that this - * {@link SwipeDismissListViewTouchListener} is paused during list view scrolling.</p> - * - * @see {@link SwipeDismissListViewTouchListener} - */ - public AbsListView.OnScrollListener makeScrollListener() { - return new AbsListView.OnScrollListener() { - @Override - public void onScrollStateChanged(AbsListView absListView, int scrollState) { - setEnabled(scrollState != AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); - } - - @Override - public void onScroll(AbsListView absListView, int i, int i1, int i2) { - } - }; - } - - /** - * Returns a {@link android.widget.AbsListView.RecyclerListener} to be added to the - * {@link ListView} using {@link ListView#setRecyclerListener(RecyclerListener)}. - */ - public AbsListView.RecyclerListener makeRecyclerListener() { - return new AbsListView.RecyclerListener() { - @Override - public void onMovedToScrapHeap(View view) { - final Object tag = view.getTag(R.id.original_height); - - // To reset the view to the correct height after its animation, the view's height - // is stored in its tag. Reset the view here. - if (tag instanceof Integer) { - view.setAlpha(1f); - view.setTranslationX(0); - final ViewGroup.LayoutParams lp = view.getLayoutParams(); - lp.height = (int) tag; - view.setLayoutParams(lp); - view.setTag(R.id.original_height, null); - } - } - }; - } - - @Override - public boolean onTouch(View view, MotionEvent motionEvent) { - if (mViewWidth < 2) { - mViewWidth = mListView.getWidth(); - } - - switch (motionEvent.getActionMasked()) { - case MotionEvent.ACTION_DOWN: { - if (mPaused) { - return false; - } - - if (mDismissing) { - return true; - } - - // TODO: ensure this is a finger, and set a flag - - // Find the child view that was touched (perform a hit test) - Rect rect = new Rect(); - int childCount = mListView.getChildCount(); - int[] listViewCoords = new int[2]; - mListView.getLocationOnScreen(listViewCoords); - int x = (int) motionEvent.getRawX() - listViewCoords[0]; - int y = (int) motionEvent.getRawY() - listViewCoords[1]; - View child; - for (int i = 0; i < childCount; i++) { - child = mListView.getChildAt(i); - child.getHitRect(rect); - if (rect.contains(x, y)) { - mDownView = child; - break; - } - } - - if (mDownView != null) { - mDownX = motionEvent.getRawX(); - mDownPosition = mListView.getPositionForView(mDownView); - - mVelocityTracker = VelocityTracker.obtain(); - mVelocityTracker.addMovement(motionEvent); - } - view.onTouchEvent(motionEvent); - return true; - } - - case MotionEvent.ACTION_UP: { - if (mVelocityTracker == null) { - break; - } - - float deltaX = motionEvent.getRawX() - mDownX; - mVelocityTracker.addMovement(motionEvent); - mVelocityTracker.computeCurrentVelocity(1000); - float velocityX = Math.abs(mVelocityTracker.getXVelocity()); - float velocityY = Math.abs(mVelocityTracker.getYVelocity()); - boolean dismiss = false; - boolean dismissRight = false; - if (Math.abs(deltaX) > mViewWidth / 2) { - dismiss = true; - dismissRight = deltaX > 0; - } else if (mMinFlingVelocity <= velocityX && velocityX <= mMaxFlingVelocity - && velocityY < velocityX) { - dismiss = true; - dismissRight = mVelocityTracker.getXVelocity() > 0; - } - if (dismiss) { - // dismiss - mDismissing = true; - final View downView = mDownView; // mDownView gets null'd before animation ends - final int downPosition = mDownPosition; - mDownView.animate() - .translationX(dismissRight ? mViewWidth : -mViewWidth) - .alpha(0) - .setDuration(mAnimationTime) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - performDismiss(downView, downPosition); - } - }); - } else { - // cancel - mDownView.animate() - .translationX(0) - .alpha(1) - .setDuration(mAnimationTime) - .setListener(null); - } - - if (mVelocityTracker != null) { - mVelocityTracker.recycle(); - mVelocityTracker = null; - } - - mDownX = 0; - mDownView = null; - mDownPosition = ListView.INVALID_POSITION; - mSwiping = false; - break; - } - - case MotionEvent.ACTION_MOVE: { - if (mVelocityTracker == null || mPaused) { - break; - } - - mVelocityTracker.addMovement(motionEvent); - float deltaX = motionEvent.getRawX() - mDownX; - if (Math.abs(deltaX) > mSlop) { - mSwiping = true; - mListView.requestDisallowInterceptTouchEvent(true); - - // Cancel ListView's touch (un-highlighting the item) - MotionEvent cancelEvent = MotionEvent.obtain(motionEvent); - cancelEvent.setAction(MotionEvent.ACTION_CANCEL | - (motionEvent.getActionIndex() - << MotionEvent.ACTION_POINTER_INDEX_SHIFT)); - mListView.onTouchEvent(cancelEvent); - cancelEvent.recycle(); - } - - if (mSwiping) { - mDownView.setTranslationX(deltaX); - mDownView.setAlpha(Math.max(0f, Math.min(1f, 1f - 2f * Math.abs(deltaX) / mViewWidth))); - return true; - } - break; - } - } - return false; - } - - /** - * Animate the dismissed list item to zero-height and fire the dismiss callback when it finishes. - * - * @param dismissView ListView item to dismiss - * @param dismissPosition Position of dismissed item - */ - private void performDismiss(final View dismissView, final int dismissPosition) { - final ViewGroup.LayoutParams lp = dismissView.getLayoutParams(); - final int originalHeight = lp.height; - - ValueAnimator animator = ValueAnimator.ofInt(dismissView.getHeight(), 1).setDuration(mAnimationTime); - - animator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - // Since the view is still a part of the ListView, we can't reset the animated - // properties yet; otherwise, the view would briefly reappear. Store the original - // height in the view's tag to flag it for the recycler. This is racy since the user - // could scroll the dismissed view off the screen, then back on the screen, before - // it's removed from the adapter, causing the dismissed view to briefly reappear. - dismissView.setTag(R.id.original_height, originalHeight); - - mCallback.onDismiss(mListView, dismissPosition); - mDismissing = false; - } - }); - - animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator valueAnimator) { - lp.height = (Integer) valueAnimator.getAnimatedValue(); - dismissView.setLayoutParams(lp); - } - }); - - animator.start(); - } -} |