美文网首页
侧滑返回效果

侧滑返回效果

作者: 菜鸟何时起飞 | 来源:发表于2020-05-19 17:14 被阅读0次
    slideback.gif

    使用

     //开启滑动返回
      SlideBack.create()
                .attachToActivity(this);
    SlideBack.create()
            .slideView(new DefaultSlideView(this))
            .attachToActivity(this);
    

    实现原理
    1 在DecorView上添加一个充满全屏的FrameLayout
    2 在FrameLayout 上添加滑动展示的view
    3 通过监听FrameLayout的触摸事件,展现不同的效果

    public class DefaultSlideView implements ISlideView {
        private Path bezierPath;
        private Paint paint, arrowPaint;
        //private LinearGradient shader;
    
        private int backViewColor = 0xff000000;
        private int arrowColor = Color.WHITE;
    
        private int arrowWidth;
    
        private final int width;
        private final int height;
    
    
        public DefaultSlideView(@NonNull Context context) {
            width = Utils.d2p(context, 50);
            height = Utils.d2p(context, 200);
            arrowWidth = Utils.d2p(context, 4);
            init(context);
        }
    
        public void setBackViewColor(int backViewColor) {
            this.backViewColor = backViewColor;
        }
    
        public void setArrowColor(int arrowColor) {
            this.arrowColor = arrowColor;
        }
    
        private void init(Context context) {
            bezierPath = new Path();
    
            paint = new Paint();
            paint.setAntiAlias(true);
            paint.setStyle(Paint.Style.FILL);
            paint.setColor(backViewColor);
            paint.setStrokeWidth(Utils.d2p(context, 1.5f));
    
            arrowPaint = new Paint();
            arrowPaint.setAntiAlias(true);
            arrowPaint.setStyle(Paint.Style.FILL_AND_STROKE);
            arrowPaint.setColor(arrowColor);
            arrowPaint.setStrokeWidth(Utils.d2p(context, 1.5f));
            arrowPaint.setStrokeCap(Paint.Cap.ROUND);
        }
    
    
        @Override
        public boolean scrollVertical() {
            return true;
        }
    
        @Override
        public int getWidth() {
            return width;
        }
    
        @Override
        public int getHeight() {
            return height;
        }
    
        @Override
        public void onDraw(Canvas canvas, float currentWidth) {
            float height = getHeight();
            int maxWidth = getWidth();
            float centerY = height / 2;
    
            float progress = currentWidth / maxWidth;
            if (progress == 0) {
                return;
            }
    
            paint.setColor(backViewColor);
            paint.setAlpha((int) (200 * progress));
    
            //画半弧背景
            /*
            ps: 小点为起始点和结束点,星号为控制点
            ·
            |
            *
                 *
                 |
                 ·
                 |
                 *
            *
            |
            ·
             */
    
            float bezierWidth = currentWidth / 2;
            bezierPath.reset();
            bezierPath.moveTo(0, 0);
            bezierPath.cubicTo(0, height / 4f, bezierWidth, height * 3f / 8, bezierWidth, centerY);
            bezierPath.cubicTo(bezierWidth, height * 5f / 8, 0, height * 3f / 4, 0, height);
            canvas.drawPath(bezierPath, paint);
    
    
            arrowPaint.setColor(arrowColor);
            arrowPaint.setAlpha((int) (255 * progress));
    
            //画箭头
            float arrowLeft = currentWidth / 6;
            if (progress <= 0.2) {
                //ingore
            } else if (progress <= 0.7f) {
                //起初变长竖直过程
                float newProgress = (progress - 0.2f) / 0.5f;
                canvas.drawLine(arrowLeft, centerY - arrowWidth * newProgress, arrowLeft, centerY + arrowWidth * newProgress, arrowPaint);
            } else {
                //后面变形到完整箭头过程
                float arrowEnd = arrowLeft + (arrowWidth * (progress - 0.7f) / 0.3f);
                canvas.drawLine(arrowEnd, centerY - arrowWidth, arrowLeft, centerY, arrowPaint);
                canvas.drawLine(arrowLeft, centerY, arrowEnd, centerY + arrowWidth, arrowPaint);
            }
    
    
        }
    }
    
    public interface ISlideView {
        /**
         * 是否可以垂直滑动
         *
         * @return
         */
        boolean scrollVertical();
    
        /**
         * 宽度
         *
         * @return
         */
        int getWidth();
    
        /**
         * 高度
         *
         * @return
         */
        int getHeight();
    
        /**
         * 绘制
         *
         * @param canvas
         * @param currentWidth 根据手指滑动得出的当前宽度(最大值为getWidth())
         */
        void onDraw(Canvas canvas, float currentWidth);
    }
    
    public interface OnSlide {
        void onSlideBack();
    }
    
    public class SlideBack {
        private ISlideView slideView;   //样式
        private OnSlide onSlide;        //滑动监听
        private int canSlideWidth;      //左边触发距离
    
        public static SlideBack create() {
            return new SlideBack();
        }
    
        /**
         * 滑动返回样式
         *
         * @param slideView the slide view
         * @return the slide back
         */
        public SlideBack slideView(ISlideView slideView) {
            this.slideView = slideView;
            return this;
        }
    
        /**
         * 左边开始触发距离
         *
         * @param canSlideWidth the can slide width
         * @return the slide back
         */
        public SlideBack canSlideWidth(int canSlideWidth) {
            this.canSlideWidth = canSlideWidth;
            return this;
        }
    
        /**
         * 滑动触发监听
         *
         * @param onSlide the on slide
         * @return the slide back
         */
        public SlideBack onSlide(OnSlide onSlide) {
            this.onSlide = onSlide;
            return this;
        }
    
    
        public SlideControlLayout attachToActivity(@NonNull Activity activity) {
            if (slideView == null) {
                slideView = new DefaultSlideView(activity);
            }
    
            if (canSlideWidth == 0) {
                canSlideWidth = Utils.d2p(activity, 18);
            }
    
            return new SlideControlLayout(activity, canSlideWidth, slideView, onSlide)
                    .attachToActivity(activity);
        }
    }
    
    class SlideBackView extends View {
        private ISlideView slideView;
        private static final DecelerateInterpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator();
        private ValueAnimator animator;
        private float rate = 0;//曲线的控制点
    
        SlideBackView(Context context, @NonNull ISlideView slideView) {
            super(context);
            setSlideView(slideView);
        }
    
        public SlideBackView setSlideView(@NonNull ISlideView slideView) {
            this.slideView = slideView;
            setLayoutParams(new SlideControlLayout.LayoutParams(slideView.getWidth(), slideView.getHeight()));
            return this;
        }
    
        public ISlideView getSlideView() {
            return slideView;
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            slideView.onDraw(canvas, rate);
        }
    
        public void updateRate(float updateRate, boolean hasAnim) {
            if (updateRate > getWidth()) {
                updateRate = getWidth();
            }
            if (rate == updateRate) {
                return;
            }
            cancelAnim();
            if (!hasAnim) {
                rate = updateRate;
                invalidate();
                if (rate == 0) {
                    setVisibility(GONE);
                }else{
                    setVisibility(VISIBLE);
                }
            }
    
            /*这个动画效果并不明显*/
            animator = ValueAnimator.ofFloat(rate, updateRate);
            animator.setDuration(200);
            animator.addUpdateListener(animation -> {
                rate = (Float) animation.getAnimatedValue();
                postInvalidate();
                if (rate == 0) {
                    setVisibility(GONE);
                }else{
                    setVisibility(VISIBLE);
                }
    
            });
            animator.setInterpolator(DECELERATE_INTERPOLATOR);
            animator.start();
        }
    
        private void cancelAnim() {
            if (animator != null && animator.isRunning()) {
                animator.cancel();
            }
        }
    
        @Override
        protected void onDetachedFromWindow() {
            cancelAnim();
            if (rate != 0) {
                rate = 0;
                invalidate();
            }
            super.onDetachedFromWindow();
        }
    
    
    }
    
    public class SlideControlLayout extends FrameLayout {
        private final SlideBackView slideBackView;
        private final OnSlide onSlide;
        private int canSlideWidth;
        private boolean enable = true;
    
        private float downX;
        private float moveX;
        private boolean startDrag = false;
    
        SlideControlLayout(@NonNull Context context, int canSlideWidth, ISlideView slideView, OnSlide onSlide) {
            super(context);
            this.canSlideWidth = canSlideWidth;
            this.onSlide = onSlide;
            slideBackView = new SlideBackView(context, slideView);
            addView(slideBackView);
        }
    
    
        SlideControlLayout attachToActivity(@NonNull Activity activity) {
            ViewParent parent = getParent();
            if (parent instanceof ViewGroup) {
                ((ViewGroup) parent).removeView(this);
            }
            ViewGroup decor = (ViewGroup) activity.getWindow().getDecorView();
    
            decor.addView(this, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
            return this;
        }
    
        private void onBack() {
            if (onSlide == null) {
                Utils.getActivityContext(getContext()).onBackPressed();
            } else {
                onSlide.onSlideBack();
            }
        }
    
    
        private void setSlideViewY(SlideBackView view, int y) {
            if (!view.getSlideView().scrollVertical()) {
                /*水平移动到0 0 点*/
                scrollTo(0, 0);
                return;
            }
            /*移动的是视图内容 移动到垂直居中*/
            scrollTo(0, -(y - view.getHeight() / 2));
        }
    
        //region 手势控制
        @Override
        public boolean onInterceptTouchEvent(MotionEvent motionEvent) {
            if (!enable) {
                return false;
            }
    
            switch (motionEvent.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    if (motionEvent.getRawX() <= canSlideWidth) {
                        return true;
                    }
            }
            return super.onInterceptTouchEvent(motionEvent);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent motionEvent) {
            if (!enable) {
                return super.onTouchEvent(motionEvent);
            }
    
            float currentX = motionEvent.getRawX();
    
            switch (motionEvent.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    float currentY = motionEvent.getRawY();
                    if (currentY > Utils.d2p(getContext(), 100) && currentX <= canSlideWidth) {
                        downX = currentX;
                        startDrag = true;
                        slideBackView.updateRate(0, false);
                        setSlideViewY(slideBackView, (int) (motionEvent.getRawY()));
                    }
                    break;
    
                case MotionEvent.ACTION_MOVE:
                    if (startDrag) {
                        moveX = currentX - downX;
                        if (Math.abs(moveX) <= slideBackView.getWidth() * 2) {
                            slideBackView.updateRate(Math.abs(moveX) / 2, false);
                        } else {
                            slideBackView.updateRate(slideBackView.getWidth(), false);
                        }
                        /*移动view*/
                        setSlideViewY(slideBackView, (int) (motionEvent.getRawY()));
                    }
                    break;
    
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                case MotionEvent.ACTION_OUTSIDE:
                    if (startDrag && moveX >= slideBackView.getWidth() * 2) {
                        onBack();
                        slideBackView.updateRate(0, false);
                    } else {
    
                        slideBackView.updateRate(0, startDrag);
                    }
                    moveX = 0;
                    startDrag = false;
                    break;
            }
    
            return startDrag || super.onTouchEvent(motionEvent);
        }
        //endregion
    
    
    }
    
    class Utils {
        @ColorInt
        static int setColorAlpha(int color, float alpha) {
            color = Color.argb((int) (alpha * 255), Color.red(color), Color.green(color), Color.blue(color));
            return color;
        }
    
        static int d2p(Context var0, float var1) {
            DisplayMetrics var2 = var0.getResources().getDisplayMetrics();
            return (int) TypedValue.applyDimension(1, var1, var2);
        }
    
        /**
         * 屏幕宽度(像素)
         */
        private static int screentwidth;
    
        static int getScreenWidth(Context context) {
            if (screentwidth > 0)
                return screentwidth;
            WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
            DisplayMetrics outMetrics = new DisplayMetrics();
            wm.getDefaultDisplay().getMetrics(outMetrics);
            return screentwidth = outMetrics.widthPixels;
        }
    
        static Activity getActivityContext(Context context) {
            if (context == null)
                return null;
            else if (context instanceof Activity)
                return (Activity) context;
            else if (context instanceof ContextWrapper)
                return getActivityContext(((ContextWrapper) context).getBaseContext());
    
            return null;
        }
    }
    

    相关文章

      网友评论

          本文标题:侧滑返回效果

          本文链接:https://www.haomeiwen.com/subject/hocqwhtx.html