0.效果图

11.gif

1.设置Activity样式属性

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

2.自定义侧边阴影视图

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.定义可滑动的Activity父类

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);
    }

    /**
     * 添加禁用滑动的子布局
     */
    public void addShieldView(View view) {
        shieldViews.add(new ShieldView(false, view));
    }

    /**
     * 添加水平禁用滑动的子布局
     */
    public void addHorizontalShieldView(View view) {
        shieldViews.add(new ShieldView(true, view));
    }

    /**
     * 移除禁用滑动的子布局
     */
    public void removeShieldView(View view) {
        for (ShieldView v : shieldViews) {
            if (v.view != null && v.view.equals(view)) {
                shieldViews.remove(v);
                break;
            }
        }
    }

    /**
     * 清空禁用滑动的子布局
     */
    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.使用

继承SlideBaseActivity类,可调用addShieldViewaddHorizontalShieldView方法解决事件冲突。

5.项目源码

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


裕谷
78 声望15 粉丝

Gitee | GitHub