Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added preDismiss Hook #17

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.example.android.swipedismiss;

import android.animation.Animator;
Expand All @@ -39,16 +38,16 @@
* 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/>
* <p>After creating the listener, the caller should also call
* {@link ListView#setOnScrollListener(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/>
* <p>Example usage:</p>
*
* <p/>
* <pre>
* SwipeDismissListViewTouchListener touchListener =
* new SwipeDismissListViewTouchListener(
Expand All @@ -64,14 +63,14 @@
* listView.setOnTouchListener(touchListener);
* listView.setOnScrollListener(touchListener.makeScrollListener());
* </pre>
*
* <p/>
* <p>This class Requires API level 12 or later due to use of {@link
* ViewPropertyAnimator}.</p>
*
* <p/>
* <p>For a generalized {@link View.OnTouchListener} that makes any view dismissable,
* see {@link SwipeDismissTouchListener}.</p>
* see {@link }.</p>
*
* @see SwipeDismissTouchListener
* @see
*/
public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
// Cached ViewConfiguration and system-wide constant values
Expand Down Expand Up @@ -116,6 +115,12 @@ public interface DismissCallbacks {
* order for convenience.
*/
void onDismiss(ListView listView, int[] reverseSortedPositions);

/**
* Called before dismissing list item. Can be used to show alert dialog to confirm removal of an item.
* @param dismissDirection
*/
void preDismiss(boolean dismissDirection);
}

/**
Expand Down Expand Up @@ -225,13 +230,7 @@ public boolean onTouch(View view, MotionEvent motionEvent) {
.setDuration(mAnimationTime)
.setListener(null);
}
mVelocityTracker.recycle();
mVelocityTracker = null;
mDownX = 0;
mDownY = 0;
mDownView = null;
mDownPosition = ListView.INVALID_POSITION;
mSwiping = false;
reset();
break;
}

Expand All @@ -258,35 +257,13 @@ public boolean onTouch(View view, MotionEvent motionEvent) {
dismissRight = mVelocityTracker.getXVelocity() > 0;
}
if (dismiss && mDownPosition != ListView.INVALID_POSITION) {
// dismiss
final View downView = mDownView; // mDownView gets null'd before animation ends
final int downPosition = mDownPosition;
++mDismissAnimationRefCount;
mDownView.animate()
.translationX(dismissRight ? mViewWidth : -mViewWidth)
.alpha(0)
.setDuration(mAnimationTime)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
performDismiss(downView, downPosition);
}
});
// pre dismiss
mCallbacks.preDismiss(dismissRight);
} else {
// cancel
mDownView.animate()
.translationX(0)
.alpha(1)
.setDuration(mAnimationTime)
.setListener(null);
onDismissCancelled();
}
mVelocityTracker.recycle();
mVelocityTracker = null;
mDownX = 0;
mDownY = 0;
mDownView = null;
mDownPosition = ListView.INVALID_POSITION;
mSwiping = false;

break;
}

Expand Down Expand Up @@ -324,6 +301,49 @@ public void onAnimationEnd(Animator animation) {
return false;
}

/**
* Called from the View Activity or Fragment if the current row can be successfully dismissed.
* @param dismissRight
*/
public void onDismissAllowed(boolean dismissRight) {
final View downView = mDownView; // mDownView gets null'd before animation ends
final int downPosition = mDownPosition;
++mDismissAnimationRefCount;
mDownView.animate()
.translationX(dismissRight ? mViewWidth : -mViewWidth)
.alpha(0)
.setDuration(mAnimationTime)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
performDismiss(downView, downPosition);
}
});
reset();
}

private void reset() {
mVelocityTracker.recycle();
mVelocityTracker = null;
mDownX = 0;
mDownY = 0;
mDownView = null;
mDownPosition = ListView.INVALID_POSITION;
mSwiping = false;
}

/**
* Called from the View Activity or Fragment if the current row should not be dismissed and revert the swipe.
*/
public void onDismissCancelled() {
mDownView.animate()
.translationX(0)
.alpha(1)
.setDuration(mAnimationTime)
.setListener(null);
reset();
}

class PendingDismissData implements Comparable<PendingDismissData> {
public int position;
public View view;
Expand Down Expand Up @@ -364,8 +384,8 @@ public void onAnimationEnd(Animator animation) {
dismissPositions[i] = mPendingDismisses.get(i).position;
}
mCallbacks.onDismiss(mListView, dismissPositions);
// Reset mDownPosition to avoid MotionEvent.ACTION_UP trying to start a dismiss

// Reset mDownPosition to avoid MotionEvent.ACTION_UP trying to start a dismiss
// animation with a stale position
mDownPosition = ListView.INVALID_POSITION;

Expand Down
86 changes: 50 additions & 36 deletions src/com/example/android/swipedismiss/SwipeDismissTouchListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.example.android.swipedismiss;

import android.animation.Animator;
Expand All @@ -32,15 +31,15 @@
/**
* A {@link View.OnTouchListener} that makes any {@link View} dismissable when the
* user swipes (drags her finger) horizontally across the view.
*
* <p/>
* <p><em>For {@link ListView} list items that don't manage their own touch events
* (i.e. you're using
* {@link ListView#setOnItemClickListener(AdapterView.OnItemClickListener)}
* or an equivalent listener on {@link ListActivity} or
* {@link ListFragment}, use {@link SwipeDismissListViewTouchListener} instead.</em></p>
*
* <p/>
* <p>Example usage:</p>
*
* <p/>
* <pre>
* view.setOnTouchListener(new SwipeDismissTouchListener(
* view,
Expand All @@ -51,7 +50,7 @@
* }
* }));
* </pre>
*
* <p/>
* <p>This class Requires API level 12 or later due to use of {@link
* android.view.ViewPropertyAnimator}.</p>
*
Expand Down Expand Up @@ -95,15 +94,22 @@ public interface DismissCallbacks {
* @param token The optional token passed to this object's constructor.
*/
void onDismiss(View view, Object token);

/**
* Called before dismissing list item. Can be used to show alert dialog to confirm removal of an item.
*
* @param dismissDirection
*/
void preDismiss(boolean dismissDirection);
}

/**
* Constructs a new swipe-to-dismiss touch listener for the given view.
*
* @param view The view to make dismissable.
* @param token An optional token/cookie object to be passed through to the callback.
* @param view The view to make dismissable.
* @param token An optional token/cookie object to be passed through to the callback.
* @param callbacks The callback to trigger when the user has indicated that she would like to
* dismiss this view.
* dismiss this view.
*/
public SwipeDismissTouchListener(View view, Object token, DismissCallbacks callbacks) {
ViewConfiguration vc = ViewConfiguration.get(view.getContext());
Expand Down Expand Up @@ -162,31 +168,12 @@ public boolean onTouch(View view, MotionEvent motionEvent) {
dismissRight = mVelocityTracker.getXVelocity() > 0;
}
if (dismiss) {
// dismiss
mView.animate()
.translationX(dismissRight ? mViewWidth : -mViewWidth)
.alpha(0)
.setDuration(mAnimationTime)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
performDismiss();
}
});
// pre dismiss
mCallbacks.preDismiss(dismissRight);
} else if (mSwiping) {
// cancel
mView.animate()
.translationX(0)
.alpha(1)
.setDuration(mAnimationTime)
.setListener(null);
onDismissCancelled();
}
mVelocityTracker.recycle();
mVelocityTracker = null;
mTranslationX = 0;
mDownX = 0;
mDownY = 0;
mSwiping = false;
break;
}

Expand All @@ -200,12 +187,7 @@ public void onAnimationEnd(Animator animation) {
.alpha(1)
.setDuration(mAnimationTime)
.setListener(null);
mVelocityTracker.recycle();
mVelocityTracker = null;
mTranslationX = 0;
mDownX = 0;
mDownY = 0;
mSwiping = false;
reset();
break;
}

Expand Down Expand Up @@ -245,6 +227,38 @@ public void onAnimationEnd(Animator animation) {
return false;
}

private void reset() {
mVelocityTracker.recycle();
mVelocityTracker = null;
mTranslationX = 0;
mDownX = 0;
mDownY = 0;
mSwiping = false;
}

public void onDismissAllowed(boolean dismissRight) {
mView.animate()
.translationX(dismissRight ? mViewWidth : -mViewWidth)
.alpha(0)
.setDuration(mAnimationTime)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
performDismiss();
}
});
reset();
}

public void onDismissCancelled() {
mView.animate()
.translationX(0)
.alpha(1)
.setDuration(mAnimationTime)
.setListener(null);
reset();
}

private void performDismiss() {
// Animate the dismissed view to zero-height and then fire the dismiss callback.
// This triggers layout on each animation frame; in the future we may want to do something
Expand Down