自定义view-侧滑返回

前言

最近发现越来越多的app中使用到侧滑返回的功能,比如微信,今日头条等等。于是我自己去实现这个功能,博客不罗嗦 尽可能的简洁一些

源码地址:https://github.com/bangbangqiu/SliddingBack.git

简要说明思路:

自定义view继承字FrameLayout,嵌套在activity的布局的最外层,作为滑动的view。重写onInterceptTouchEvent()方法拦截滑动事件,在onTouchEvent中根据滑动距离调用View的scroolTo()方法。手指松开 计算滑动速度和滑动距离是否达到activity销毁的大小,并提供销毁的回调方法。在Style.xml中配置activity的样式位背景透明

具体解析及代码:

 @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //如果点击距离屏幕左边界10dp,触发返回销毁activity
        float x = ev.getX();
        Log.d(TAG, "onInterceptTouchEvent: x:" + ev.getX());
        if (!isOpen) return false;
        if (x < dp2px(sliddingLength)) {
            //注意: 即使拦截 ACTION_DOWN 也会执行一次
            isInterupt = true;
        } else {
            isInterupt = false;
        }
        return isInterupt;
    }

如果按下的点在滑动的区域内就 return true 拦截事件,交给onTouchEvent()处理


@Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG, "onTouchEvent: x:" + event.getX() + "y: " + event.getY());
        Log.d(TAG, "onTouchEvent: downX:" + downPoint.x + "downY: " + downPoint.y);
        Log.d(TAG, "onTouchEvent: currentX:" + currentPoint.x + "currentY: " + currentPoint.y);
        //当 isInterrupt==false 或者不在拦截区域 进行拦截
        if (!isInterupt || downPoint.x > dp2px(sliddingLength)) {
            Log.d(TAG, "onTouchEvent: 拦截==================");
            return false;
        }
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.d(TAG, "onTouchEvent: ACTION_DOWN");
                currentPoint.x = downPoint.x = (int) event.getX();
                currentPoint.y = downPoint.y = (int) event.getY();
                startTime = System.currentTimeMillis();
                break;
            case MotionEvent.ACTION_MOVE:
//                Log.d(TAG, "onTouchEvent: ACTION_MOVE");
                //滑动操作
                speed = (int) ((event.getX() - currentPoint.x) / (System.currentTimeMillis() - startTime) * 1000);
                Log.d(TAG, "onTouchEvent: speed: " + speed);
                scrollTo(downPoint.x - currentPoint.x, 0);
                currentPoint.x = (int) event.getX();
                currentPoint.y = (int) event.getY();
                startTime = System.currentTimeMillis();
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                Log.d(TAG, "onTouchEvent: ACTION_UP_CANCEL");
                int x = (int) event.getX();
                //如果速度达到了,并且是正值,负数代表反方向
                if (speed > 1000) {
                    finish();
                    return true;
                }
                if (x < 0.3 * widthPixels || speed < -1000) {
//                    Toast.makeText(getContext(), "距离不够activity不销毁", Toast.LENGTH_SHORT).show();
                    backActivityListenner.onSliddingOver(false);
                    backAnimation(currentPoint.x, 0);
                } else {
//                    Toast.makeText(getContext(), "距离达到activity销毁", Toast.LENGTH_SHORT).show();
                    finish();
                }
                //初始化
                downPoint.set(1, 0);
                currentPoint.set(0, 0);
                break;
        }
        return true;
    }


不多说了,都在代码中了。完成这两个方法就可以 滑动了

添加动画和绘制引用

 //回复动画
    public void backAnimation(final int xStart, final int xEnd) {
        final ValueAnimator animator = ValueAnimator.ofInt(xStart, xEnd);
        animator.setInterpolator(new AccelerateInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int animatedValue = (int) animation.getAnimatedValue();
                scrollTo(-animatedValue, 0);
                Log.d(TAG, "onAnimationUpdate: " + animatedValue);
                if (animatedValue == xEnd) {
                    animator.removeUpdateListener(this);
                }
            }
        });
        animator.setDuration(duration);
        animator.start();
    }

通过valueAnimator根据值的渐变做动画,记得完成动画后移除监听,防止内存泄漏。


  @Override
    protected void onDraw(Canvas canvas) {
        //绘制阴影
        Log.d(TAG, "onDraw: width " + getWidth());
        canvas.drawRect(shaderRectF, fillPaint);
        super.onDraw(canvas);
    }


在onDraw()中去绘制阴影,带渐变色的,很简洁。注意:在构造函数中加上 setWillNotDraw ( false );否则onDraw()方法不执行。。


 public interface BackActivityListenner {
        void onSliddingOver(boolean canBack);
    }
    public Point getCurrentPoint() {
        return currentPoint;
    }

对外提供达到activity可销毁的监听



很重要的一点:设置透明的样式。


效果(项目中测试)
自定义view-侧滑返回_第1张图片
结语 

写的第一篇博客献丑了,技术含量不高

你可能感兴趣的:(控件)