link.fls.swipestack.SwipeHelper.java Source code

Java tutorial

Introduction

Here is the source code for link.fls.swipestack.SwipeHelper.java

Source

/*
 * Copyright (C) 2016 Frederik Schweiger
 *
 * 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 link.fls.swipestack;

import android.animation.Animator;
import android.content.Context;
import android.support.v4.view.GestureDetectorCompat;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.OvershootInterpolator;

import link.fls.swipestack.util.AnimationUtils;

public class SwipeHelper implements View.OnTouchListener {

    private final SwipeStack mSwipeStack;
    private View mObservedView;

    private boolean mListenForTouchEvents;
    private float mDownX;
    private float mDownY;
    private float mInitialX;
    private float mInitialY;
    private int mPointerId;

    private float mRotateDegrees = SwipeStack.DEFAULT_SWIPE_ROTATION;
    private float mOpacityEnd = SwipeStack.DEFAULT_SWIPE_OPACITY;
    private int mAnimationDuration = SwipeStack.DEFAULT_ANIMATION_DURATION;

    private GestureDetectorCompat gestureDetector;

    public SwipeHelper(Context context, SwipeStack swipeStack) {
        mSwipeStack = swipeStack;
        gestureDetector = new GestureDetectorCompat(context, new SingleTapConfirm());
        gestureDetector.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener() {
            @Override
            public boolean onSingleTapConfirmed(MotionEvent e) {
                mSwipeStack.onSwipeTap();
                return false;
            }

            @Override
            public boolean onDoubleTap(MotionEvent e) {
                return false;
            }

            @Override
            public boolean onDoubleTapEvent(MotionEvent e) {
                return false;
            }
        });
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {

        try {

            if (gestureDetector.onTouchEvent(event)) {
                // we want to catch the use-cases in the gesture detector
                return true;
            } else {
                // otherwise do you dragging animation job
                switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    if (!mListenForTouchEvents || !mSwipeStack.isEnabled()) {
                        return false;
                    }

                    v.getParent().requestDisallowInterceptTouchEvent(true);
                    mSwipeStack.onSwipeStart();
                    mPointerId = event.getPointerId(0);
                    mDownX = event.getX(mPointerId);
                    mDownY = event.getY(mPointerId);

                    return true;

                case MotionEvent.ACTION_MOVE:
                    int pointerIndex = event.findPointerIndex(mPointerId);
                    if (pointerIndex < 0)
                        return false;

                    float dx = event.getX(pointerIndex) - mDownX;
                    float dy = event.getY(pointerIndex) - mDownY;

                    float newX = mObservedView.getX() + dx;
                    float newY = mObservedView.getY() + dy;

                    mObservedView.setX(newX);
                    mObservedView.setY(newY);

                    float dragDistanceX = newX - mInitialX;
                    float swipeProgress = Math.min(Math.max(dragDistanceX / mSwipeStack.getWidth(), -1), 1);

                    mSwipeStack.onSwipeProgress(swipeProgress);

                    if (mRotateDegrees > 0) {
                        float rotation = mRotateDegrees * swipeProgress;
                        mObservedView.setRotation(rotation);
                    }

                    if (mOpacityEnd < 1f) {
                        float alpha = 1 - Math.min(Math.abs(swipeProgress * 2), 1);
                        mObservedView.setAlpha(alpha);
                    }

                    return true;

                case MotionEvent.ACTION_UP:

                    v.getParent().requestDisallowInterceptTouchEvent(false);
                    mSwipeStack.onSwipeEnd();
                    checkViewPosition();

                    return true;
                }
            }
        } catch (IllegalArgumentException iae) {
            //The same bug
            //https://github.com/chrisbanes/PhotoView/blob/92a2a281134ceddc6e402ba4a83cc91180db8115/sample/src/uk/co/senab/photoview/sample/HackyViewPager.java
            return false;
        }

        return false;
    }

    private void checkViewPosition() {
        if (!mSwipeStack.isEnabled()) {
            resetViewPosition();
            return;
        }

        float viewCenterHorizontal = mObservedView.getX() + (mObservedView.getWidth() / 2);
        float parentFirstThird = mSwipeStack.getWidth() / 3f;
        float parentLastThird = parentFirstThird * 2;

        if (viewCenterHorizontal < parentFirstThird
                && mSwipeStack.getAllowedSwipeDirections() != SwipeStack.SWIPE_DIRECTION_ONLY_RIGHT) {
            swipeViewToLeft(mAnimationDuration / 2);
        } else if (viewCenterHorizontal > parentLastThird
                && mSwipeStack.getAllowedSwipeDirections() != SwipeStack.SWIPE_DIRECTION_ONLY_LEFT) {
            swipeViewToRight(mAnimationDuration / 2);
        } else {
            resetViewPosition();
        }
    }

    private void resetViewPosition() {
        mObservedView.animate().x(mInitialX).y(mInitialY).rotation(0).alpha(1).setDuration(mAnimationDuration)
                .setInterpolator(new OvershootInterpolator(1.4f)).setListener(null);
    }

    private void swipeViewToLeft(int duration) {
        if (!mListenForTouchEvents)
            return;
        mListenForTouchEvents = false;
        mObservedView.animate().cancel();
        mObservedView.animate().x(-mSwipeStack.getWidth() + mObservedView.getX()).rotation(-mRotateDegrees)
                .alpha(0f).setDuration(duration).setListener(new AnimationUtils.AnimationEndListener() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        mSwipeStack.onViewSwipedToLeft();
                    }
                });
    }

    private void swipeViewToRight(int duration) {
        if (!mListenForTouchEvents)
            return;
        mListenForTouchEvents = false;
        mObservedView.animate().cancel();
        mObservedView.animate().x(mSwipeStack.getWidth() + mObservedView.getX()).rotation(mRotateDegrees).alpha(0f)
                .setDuration(duration).setListener(new AnimationUtils.AnimationEndListener() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        mSwipeStack.onViewSwipedToRight();
                    }
                });
    }

    public void registerObservedView(View view, float initialX, float initialY) {
        if (view == null)
            return;
        mObservedView = view;
        mObservedView.setOnTouchListener(this);
        mInitialX = initialX;
        mInitialY = initialY;
        mListenForTouchEvents = true;
    }

    public void unregisterObservedView() {
        if (mObservedView != null) {
            mObservedView.setOnTouchListener(null);
        }
        mObservedView = null;
        mListenForTouchEvents = false;
    }

    public void setAnimationDuration(int duration) {
        mAnimationDuration = duration;
    }

    public void setRotation(float rotation) {
        mRotateDegrees = rotation;
    }

    public void setOpacityEnd(float alpha) {
        mOpacityEnd = alpha;
    }

    public void swipeViewToLeft() {
        swipeViewToLeft(mAnimationDuration);
    }

    public void swipeViewToRight() {
        swipeViewToRight(mAnimationDuration);
    }

    private class SingleTapConfirm implements GestureDetector.OnGestureListener {

        @Override
        public boolean onDown(MotionEvent e) {
            return false;
        }

        @Override
        public void onShowPress(MotionEvent e) {

        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            return false;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            return false;
        }

        @Override
        public void onLongPress(MotionEvent e) {

        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            return false;
        }
    }
}