Android Sideswipe to close activity

Time:2021-3-27

0. Renderings

Android Sideswipe to close activity

1. Set the activity style property

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowIsTranslucent">true</item>
</style>

2. Custom side shadow view

class SlideBackView extends View {

        private Paint mBgPaint, mShadowPaint;
        private RectF mBgRectF, mShadowRectF;
        private float mRatio;
        private float mShadowSize;

        public SlideBackView(Context context) {
            super(context);
            mBgPaint = new Paint();
            mBgPaint.setAntiAlias(true);
            mBgPaint.setColor(0xff000000);
            mShadowPaint = new Paint();
            mShadowPaint.setAntiAlias(true);
            mShadowPaint.setStyle(Paint.Style.FILL);
            mShadowSize = dp2px(15);
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            mBgRectF = new RectF();
            mBgRectF.top = 0;
            mBgRectF.left = 0;
            mBgRectF.bottom = MeasureSpec.getSize(heightMeasureSpec);

            mShadowRectF = new RectF();
            mShadowRectF.top = 0;
            mShadowRectF.bottom = MeasureSpec.getSize(heightMeasureSpec);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            int width = getMeasuredWidth();
            float right = mRatio * width;
            mBgRectF.right = right;
            mBgPaint.setAlpha((int) (128 * (1 - mRatio)));
            canvas.drawRect(mBgRectF, mBgPaint);
            mShadowRectF.left = right - mShadowSize;
            mShadowRectF.right = right;
            mShadowPaint.setShader(new LinearGradient(mShadowRectF.left, 0, mShadowRectF.right, 0, 0x00000000, 0x26000000, Shader.TileMode.CLAMP));
            canvas.drawRect(mShadowRectF, mShadowPaint);
        }

        public void setDistance(float ratio) {
            mRatio = ratio;
            invalidate();
        }

        private float dp2px(float dpValue) {
            float density = getResources().getDisplayMetrics().density;
            return dpValue * density + 0.5F;
        }
    }

3. Define the sliding activity parent class

public class SlideBaseActivity extends AppCompatActivity implements ValueAnimator.AnimatorUpdateListener {

    private boolean isAnimate, isSlide, isHandle;
    private float moveNum;
    private float lastX, lastY;
    private int lastPointerCount;
    private float mAnimatedValue;
    private ValueAnimator mValueAnimator;
    private SlideBackView mSlideBackView;
    private float mTouchSlop;
    private List<ShieldView> shieldViews = new ArrayList<>();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        super.onCreate(savedInstanceState);
        initAnimator();
        initSlideBackView();
        mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
    }

    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        mAnimatedValue = (float) animation.getAnimatedValue();
        moveView(mAnimatedValue);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (!isAnimate) {
            float x = event.getRawX();
            float y = event.getRawY();
            if (event.getPointerCount() != lastPointerCount) {
                lastPointerCount = event.getPointerCount();
                lastX = x;
                lastY = y;
            }
            float offsetX, offsetY;
            switch (event.getAction()) {
                case MotionEvent.ACTION_MOVE:
                    offsetX = x - lastX;
                    offsetY = y - lastY;
                    if (!isHandle) {
                        float absX = Math.abs(offsetX);
                        float absY = Math.abs(offsetY);
                        if (absX > mTouchSlop) {
                            if (absX * 0.5f > absY) {
                                isSlide = true;
                                checkSlide((int) x, (int) y);
                            } else {
                                isSlide = false;
                            }
                            isHandle = true;
                        }
                    } else if (isSlide) {
                        moveNum += offsetX;
                        if (moveNum < 0) {
                            moveNum = 0;
                        }
                        moveView(moveNum);
                        lastX = event.getX();
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    if (isHandle) {
                        isSlide = false;
                        isHandle = false;
                        isAnimate = true;
                        int width = getWindow().getDecorView().getMeasuredWidth();
                        if (moveNum < width / 3f) {
                            mValueAnimator.setFloatValues(moveNum, 0);
                        } else {
                            mValueAnimator.setFloatValues(moveNum, width);
                        }
                        mValueAnimator.start();
                        moveNum = 0;
                        lastPointerCount = 0;
                    }
            }
        }
        return isSlide || super.dispatchTouchEvent(event);
    }

    /**
     *Add sliding disabled sub layout
     */
    public void addShieldView(View view) {
        shieldViews.add(new ShieldView(false, view));
    }

    /**
     *Add sub layout with horizontal slide disabled
     */
    public void addHorizontalShieldView(View view) {
        shieldViews.add(new ShieldView(true, view));
    }

    /**
     *Remove sub layout with slide disabled
     */
    public void removeShieldView(View view) {
        for (ShieldView v : shieldViews) {
            if (v.view != null && v.view.equals(view)) {
                shieldViews.remove(v);
                break;
            }
        }
    }

    /**
     *Clear sub layout with slide disabled
     */
    public void clearShieldView() {
        shieldViews.clear();
    }

    private void initAnimator() {
        mValueAnimator = new ValueAnimator();
        mValueAnimator.setDuration(300);
        mValueAnimator.addUpdateListener(this);
        mValueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                isAnimate = false;
                if (mAnimatedValue == getWindow().getDecorView().getMeasuredWidth()) {
                    SlideBaseActivity.super.finish();
                    overridePendingTransition(0, 0);
                }
            }
        });
    }

    private void initSlideBackView() {
        mSlideBackView = new SlideBackView(this);
        ViewGroup decorView = (ViewGroup) getWindow().getDecorView();
        decorView.addView(mSlideBackView);
    }

    private void moveView(float moveX) {
        ViewGroup decorView = (ViewGroup) getWindow().getDecorView();
        mSlideBackView.setDistance(moveX / decorView.getMeasuredWidth());
        int count = decorView.getChildCount();
        for (int i = 0; i < count; i++) {
            View view = decorView.getChildAt(i);
            if (view != mSlideBackView) {
                view.setX(moveX);
            }
        }
    }

    private void checkSlide(int x, int y) {
        for (ShieldView v : shieldViews) {
            Rect rect = new Rect();
            v.view.getGlobalVisibleRect(rect);
            if (rect.contains(x, y) && (!(lastX < x && !v.view.canScrollHorizontally(-1)) || (!v.isHorizontal))) {
                isSlide = false;
            }
        }
    }
    
    class ShieldView {
        boolean isHorizontal;
        View view;

        public ShieldView(boolean isHorizontal, View view) {
            this.isHorizontal = isHorizontal;
            this.view = view;
        }
    }
}

4. Use

inheritSlideBaseActivityClass, callableaddShieldVieworaddHorizontalShieldViewMethod to resolve the event conflict.

5. Project source code

https://gitee.com/yugu/slide-demo

Recommended Today

Deeply analyze the principle and practice of RSA key

1、 Preface After experiencing many dark moments in life, when you read this article, you will regret and even be angry: why didn’t you write this article earlier?! Your darkest moments include: 1. Your project needs to be connected with the bank, and the other party needs you to provide an encryption certificate. You have […]