Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public class SwipeableRecyclerViewTouchListener implements RecyclerView.OnItemTouchListener {
- // Cached ViewConfiguration and system-wide constant values
- private int mSlop;
- private int mMinFlingVelocity;
- private int mMaxFlingVelocity;
- private long mAnimationTime;
- // Fixed properties
- private RecyclerView mRecyclerView;
- private SwipeListener mSwipeListener;
- private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero
- // Transient properties
- private List<PendingDismissData> mPendingDismisses = new ArrayList<>();
- private int mDismissAnimationRefCount = 0;
- private float mDownX;
- private float mDownY;
- private boolean mSwiping;
- private int mSwipingSlop;
- private VelocityTracker mVelocityTracker;
- private int mDownPosition;
- private View mDownView;
- private boolean mPaused;
- private float mFinalDelta;
- /**
- * Constructs a new swipe touch listener for the given {@link android.support.v7.widget.RecyclerView}
- *
- * @param recyclerView The recycler view whose items should be dismissable by swiping.
- * @param listener The listener for the swipe events.
- */
- public SwipeableRecyclerViewTouchListener(RecyclerView recyclerView, SwipeListener listener) {
- ViewConfiguration vc = ViewConfiguration.get(recyclerView.getContext());
- mSlop = vc.getScaledTouchSlop();
- mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * 16;
- mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
- mAnimationTime = recyclerView.getContext().getResources().getInteger(
- android.R.integer.config_shortAnimTime);
- mRecyclerView = recyclerView;
- mSwipeListener = listener;
- /**
- * This will ensure that this SwipeableRecyclerViewTouchListener is paused during list view scrolling.
- * If a scroll listener is already assigned, the caller should still pass scroll changes through
- * to this listener.
- */
- mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
- @Override
- public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
- setEnabled(newState != RecyclerView.SCROLL_STATE_DRAGGING);
- }
- @Override
- public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
- }
- });
- }
- /**
- * 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;
- }
- @Override
- public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent motionEvent) {
- return handleTouchEvent(motionEvent);
- }
- @Override
- public void onTouchEvent(RecyclerView rv, MotionEvent motionEvent) {
- handleTouchEvent(motionEvent);
- }
- private boolean handleTouchEvent(MotionEvent motionEvent) {
- if (mViewWidth < 2) {
- mViewWidth = mRecyclerView.getWidth();
- }
- switch (motionEvent.getActionMasked()) {
- case MotionEvent.ACTION_DOWN: {
- if (mPaused) {
- break;
- }
- // Find the child view that was touched (perform a hit test)
- Rect rect = new Rect();
- int childCount = mRecyclerView.getChildCount();
- int[] listViewCoords = new int[2];
- mRecyclerView.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 = mRecyclerView.getChildAt(i);
- child.getHitRect(rect);
- if (rect.contains(x, y)) {
- mDownView = child;
- break;
- }
- }
- if (mDownView != null) {
- mDownX = motionEvent.getRawX();
- mDownY = motionEvent.getRawY();
- mDownPosition = mRecyclerView.getChildPosition(mDownView);
- if (mSwipeListener.canSwipe(mDownPosition)) {
- mVelocityTracker = VelocityTracker.obtain();
- mVelocityTracker.addMovement(motionEvent);
- } else {
- mDownView = null;
- }
- }
- break;
- }
- case MotionEvent.ACTION_CANCEL: {
- if (mVelocityTracker == null) {
- break;
- }
- if (mDownView != null && mSwiping) {
- // cancel
- mDownView.animate()
- .translationX(0)
- .alpha(1)
- .setDuration(mAnimationTime)
- .setListener(null);
- }
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- mDownX = 0;
- mDownY = 0;
- mDownView = null;
- mDownPosition = ListView.INVALID_POSITION;
- mSwiping = false;
- break;
- }
- case MotionEvent.ACTION_UP: {
- if (mVelocityTracker == null) {
- break;
- }
- mFinalDelta = motionEvent.getRawX() - mDownX;
- mVelocityTracker.addMovement(motionEvent);
- mVelocityTracker.computeCurrentVelocity(1000);
- float velocityX = mVelocityTracker.getXVelocity();
- float absVelocityX = Math.abs(velocityX);
- float absVelocityY = Math.abs(mVelocityTracker.getYVelocity());
- boolean dismiss = false;
- boolean dismissRight = false;
- if (Math.abs(mFinalDelta) > mViewWidth / 2 && mSwiping) {
- dismiss = true;
- dismissRight = mFinalDelta > 0;
- } else if (mMinFlingVelocity <= absVelocityX && absVelocityX <= mMaxFlingVelocity
- && absVelocityY < absVelocityX && mSwiping) {
- // dismiss only if flinging in the same direction as dragging
- dismiss = (velocityX < 0) == (mFinalDelta < 0);
- dismissRight = mVelocityTracker.getXVelocity() > 0;
- }
- if(!dismiss) {
- mDownView.animate()
- .translationX(0)
- .alpha(1)
- .setDuration(mAnimationTime)
- .setListener(null);
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- mDownX = 0;
- mDownY = 0;
- mDownView = null;
- mDownPosition = ListView.INVALID_POSITION;
- mSwiping = false;
- Log.d("if!dismiss", "here now");
- }
- if (dismiss && mDownPosition != ListView.INVALID_POSITION) {
- // dismiss
- final View downView = mDownView; // mDownView gets null'd before animation ends
- final int downPosition = mDownPosition;
- ++mDismissAnimationRefCount;
- final SweetAlertDialog dialog = new SweetAlertDialog(mRecyclerView.getContext(), SweetAlertDialog.WARNING_TYPE);
- dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
- @Override
- public void onDismiss(DialogInterface dialog) {
- mRecyclerView.invalidateItemDecorations();
- }
- });
- final boolean finalDismissRight = dismissRight;
- dialog
- .setTitleText("Are you sure?")
- .setContentText("Won't be able to recover this file!")
- .setCancelText("No,cancel plx!")
- .setConfirmText("Yes,delete it!")
- .showCancelButton(true)
- .setCancelClickListener(new SweetAlertDialog.OnSweetClickListener() {
- @Override
- public void onClick(SweetAlertDialog sDialog) {
- sDialog.dismiss();
- dialog.dismiss();
- if(mDownView != null) {
- mDownView.animate()
- .translationX(0)
- .alpha(1)
- .setDuration(mAnimationTime)
- .setListener(null);
- Log.d("CancelClickListener", "If statement");
- mRecyclerView.invalidateItemDecorations();
- }
- else {
- downView.animate()
- .translationX(0)
- .alpha(1)
- .setDuration(mAnimationTime)
- .setListener(null);
- Log.d("CancelClickListener", "Else statement");
- mRecyclerView.invalidateItemDecorations();
- }
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- mDownX = 0;
- mDownY = 0;
- mDownView = null;
- mDownPosition = ListView.INVALID_POSITION;
- mSwiping = false;
- Log.d("CancelClickListener", "After if and else statement");
- mRecyclerView.invalidateItemDecorations();
- sDialog.dismiss();
- }
- })
- .setConfirmClickListener(new SweetAlertDialog.OnSweetClickListener() {
- @Override
- public void onClick(SweetAlertDialog sweetAlertDialog) {
- dialog.cancel();
- new SweetAlertDialog(sweetAlertDialog.getContext(), SweetAlertDialog.SUCCESS_TYPE)
- .setTitleText("Good job!")
- .setContentText("You clicked the button!")
- .show();
- mDownView.animate()
- .translationX(finalDismissRight ? mViewWidth : -mViewWidth)
- .alpha(0)
- .setDuration(mAnimationTime)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- performDismiss(downView, downPosition);
- Log.d("ConfirmClickListener", "OnAnimationEnd");
- }
- });
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- mDownX = 0;
- mDownY = 0;
- mDownView = null;
- mDownPosition = ListView.INVALID_POSITION;
- mSwiping = false;
- }
- })
- .show();
- }
- break;
- }
- case MotionEvent.ACTION_MOVE: {
- if (mVelocityTracker == null || mPaused) {
- break;
- }
- mVelocityTracker.addMovement(motionEvent);
- float deltaX = motionEvent.getRawX() - mDownX;
- float deltaY = motionEvent.getRawY() - mDownY;
- if (!mSwiping && Math.abs(deltaX) > mSlop && Math.abs(deltaY) < Math.abs(deltaX) / 2) {
- mSwiping = true;
- mSwipingSlop = (deltaX > 0 ? mSlop : -mSlop);
- }
- if (mSwiping) {
- mDownView.setTranslationX(deltaX - mSwipingSlop);
- mDownView.setAlpha(Math.max(0f, Math.min(1f,
- 1f - Math.abs(deltaX) / mViewWidth)));
- return true;
- }
- break;
- }
- }
- return false;
- }
- private void performDismiss(final View dismissView, final int dismissPosition) {
- // Animate the dismissed list item to zero-height and fire the dismiss callback when
- // all dismissed list item animations have completed. This triggers layout on each animation
- // frame; in the future we may want to do something smarter and more performant.
- final ViewGroup.LayoutParams lp = dismissView.getLayoutParams();
- final int originalHeight = dismissView.getHeight();
- ValueAnimator animator = ValueAnimator.ofInt(originalHeight, 1).setDuration(mAnimationTime);
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- --mDismissAnimationRefCount;
- if (mDismissAnimationRefCount == 0) {
- // No active animations, process all pending dismisses.
- // Sort by descending position
- Collections.sort(mPendingDismisses);
- int[] dismissPositions = new int[mPendingDismisses.size()];
- for (int i = mPendingDismisses.size() - 1; i >= 0; i--) {
- dismissPositions[i] = mPendingDismisses.get(i).position;
- }
- if (mFinalDelta > 0) {
- mSwipeListener.onDismissedBySwipeRight(mRecyclerView, dismissPositions);
- } else {
- mSwipeListener.onDismissedBySwipeLeft(mRecyclerView, dismissPositions);
- }
- // Reset mDownPosition to avoid MotionEvent.ACTION_UP trying to start a dismiss
- // animation with a stale position
- mDownPosition = ListView.INVALID_POSITION;
- ViewGroup.LayoutParams lp;
- for (PendingDismissData pendingDismiss : mPendingDismisses) {
- // Reset view presentation
- pendingDismiss.view.setAlpha(1f);
- pendingDismiss.view.setTranslationX(0);
- lp = pendingDismiss.view.getLayoutParams();
- lp.height = originalHeight;
- pendingDismiss.view.setLayoutParams(lp);
- }
- // Send a cancel event
- long time = SystemClock.uptimeMillis();
- MotionEvent cancelEvent = MotionEvent.obtain(time, time,
- MotionEvent.ACTION_CANCEL, 0, 0, 0);
- mRecyclerView.dispatchTouchEvent(cancelEvent);
- mPendingDismisses.clear();
- }
- }
- });
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator valueAnimator) {
- lp.height = (Integer) valueAnimator.getAnimatedValue();
- dismissView.setLayoutParams(lp);
- }
- });
- mPendingDismisses.add(new PendingDismissData(dismissPosition, dismissView));
- animator.start();
- }
- /**
- * The callback interface used by {@link SwipeableRecyclerViewTouchListener} to inform its client
- * about a swipe of one or more list item positions.
- */
- public interface SwipeListener {
- /**
- * Called to determine whether the given position can be swiped.
- */
- boolean canSwipe(int position);
- /**
- * Called when the item has been dismissed by swiping to the left.
- *
- * @param recyclerView The originating {@link android.support.v7.widget.RecyclerView}.
- * @param reverseSortedPositions An array of positions to dismiss, sorted in descending
- * order for convenience.
- */
- void onDismissedBySwipeLeft(RecyclerView recyclerView, int[] reverseSortedPositions);
- /**
- * Called when the item has been dismissed by swiping to the right.
- *
- * @param recyclerView The originating {@link android.support.v7.widget.RecyclerView}.
- * @param reverseSortedPositions An array of positions to dismiss, sorted in descending
- * order for convenience.
- */
- void onDismissedBySwipeRight(RecyclerView recyclerView, int[] reverseSortedPositions);
- }
- class PendingDismissData implements Comparable<PendingDismissData> {
- public int position;
- public View view;
- public PendingDismissData(int position, View view) {
- this.position = position;
- this.view = view;
- }
- @Override
- public int compareTo(@NonNull PendingDismissData other) {
- // Sort by descending position
- return other.position - position;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement