美文网首页高级UI
侧滑效果[第十一篇]:侧滑框架SmartSwipe之贝塞尔曲线返

侧滑效果[第十一篇]:侧滑框架SmartSwipe之贝塞尔曲线返

作者: NoBugException | 来源:发表于2019-11-21 16:34 被阅读0次

首先看下效果:

293.gif

当向右滑动时,左边边界会出现一个滴水图标,这个图标的绘制原理是:贝塞尔曲线。

SmartSwipe框架中使用BezierBackConsumer来实现这个效果,BezierBackConsumer代码如下:

/**
 * swipe to back with bezier consumer
 * thanks:
 *  1. https://github.com/qinci/AndroidSlideBack
 *  2. https://github.com/Blankj/SwipePanel
 * @author billy.qi
 */
public class BezierBackConsumer extends SwipeConsumer {
    protected float mThickness, mLastThickness;

    protected final Paint mPaint = new Paint();
    protected final Path mPath = new Path();
    protected final PointF mPathStart = new PointF();
    protected final PointF mPathControl1 = new PointF();
    protected final PointF mPathControl2 = new PointF();
    protected final PointF mPathControl = new PointF();
    protected final PointF mPathControl3 = new PointF();
    protected final PointF mPathControl4 = new PointF();
    protected final PointF mPathEnd = new PointF();

    protected final Paint mPaintArrow = new Paint();
    protected final Path mPathArrow = new Path();
    protected Rect mDrawRect = new Rect();
    protected int mArrowSize;
    protected int mSize;
    protected int mColor;
    protected int mArrowColor = 0xFFF2F2F2;
    protected boolean mCenter;

    public BezierBackConsumer() {
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
        mPaintArrow.setAntiAlias(true);
        mPaintArrow.setStyle(Paint.Style.STROKE);
        mPaintArrow.setColor(mArrowColor);
        mPaintArrow.setStrokeWidth(4);
        mPaintArrow.setStrokeCap(Paint.Cap.ROUND);
    }

    @Override
    public void onAttachToWrapper(SmartSwipeWrapper wrapper, SwipeHelper swipeHelper) {
        Context context = wrapper.getContext();
        if (mSize == 0) {
            mSize = SmartSwipe.dp2px(200, context);
        }
        if (mArrowSize == 0) {
            mArrowSize = SmartSwipe.dp2px(4, context);
        }
        if (mOpenDistance == 0) {
            mOpenDistance = SmartSwipe.dp2px(30, context);
        }
        super.onAttachToWrapper(wrapper, swipeHelper);
    }

    @Override
    public void onSwipeAccepted(int activePointerId, boolean settling, float initialMotionX, float initialMotionY) {
        super.onSwipeAccepted(activePointerId, settling, initialMotionX, initialMotionY);
        // init bezier positions
        boolean left = mDirection == DIRECTION_LEFT;
        boolean right = mDirection == DIRECTION_RIGHT;
        boolean top = mDirection == DIRECTION_TOP;
        boolean horizontal = left || right;

        int thickness = mOpenDistance;
        boolean isCenter = settling || isCenter();

        int halfSize = Math.min(mSize, horizontal ? mHeight : mWidth) >> 1;
        int quarterSize =  halfSize >> 2;
        float middleX = horizontal ? (left ? 0 : mWidth) : (isCenter ? mWidth >> 1 : SmartSwipe.ensureBetween(initialMotionX, halfSize, mWidth - halfSize));
        float middleY = !horizontal ? (top ? 0 : mHeight) : (isCenter ? mHeight >> 1 : SmartSwipe.ensureBetween(initialMotionY, halfSize, mHeight - halfSize));

        mPathStart.set(horizontal ? middleX : middleX - halfSize, horizontal ? middleY - halfSize : middleY);
        mPathControl1.set(horizontal ? middleX : middleX - quarterSize, horizontal ? middleY - quarterSize : middleY);
        mPathControl2.set(mPathControl1.x, mPathControl1.y);
        mPathControl.set(middleX, middleY);
        mPathControl3.set(horizontal ? middleX : middleX + quarterSize, horizontal ? middleY + quarterSize : middleY);
        mPathControl4.set(mPathControl3.x, mPathControl3.y);
        mPathEnd.set(horizontal ? middleX : middleX + halfSize, horizontal ? middleY + halfSize : middleY);

        mDrawRect.left = horizontal ? left ? 0 : mWidth - thickness : (int) mPathStart.x;
        mDrawRect.top = horizontal ? (int) mPathStart.y : top ? 0 : mHeight - thickness;
        mDrawRect.right = horizontal ? left ? thickness : mWidth : (int) mPathEnd.x;
        mDrawRect.bottom = horizontal ? (int) mPathEnd.y : top ? thickness : mHeight;

    }

    @Override
    public void onDisplayDistanceChanged(int distanceXToDisplay, int distanceYToDisplay, int dx, int dy) {
        if ((mDirection & DIRECTION_HORIZONTAL) != 0) {
            mThickness = Math.abs(distanceXToDisplay);
        } else if ((mDirection & DIRECTION_VERTICAL) != 0) {
            mThickness = Math.abs(distanceYToDisplay);
        } else {
            return;
        }
        if (mThickness != mLastThickness) {
            ViewCompat.postInvalidateOnAnimation(mWrapper);
        }
        mLastThickness = mThickness;
    }

    @Override
    public void dispatchDraw(Canvas canvas) {
        switch (mDirection) {
            case DIRECTION_LEFT:    mPathControl3.x = mPathControl2.x = mPathControl.x = mThickness; break;
            case DIRECTION_RIGHT:   mPathControl3.x = mPathControl2.x = mPathControl.x = mWidth - mThickness; break;
            case DIRECTION_TOP:     mPathControl3.y = mPathControl2.y = mPathControl.y = mThickness; break;
            case DIRECTION_BOTTOM:  mPathControl3.y = mPathControl2.y = mPathControl.y = mHeight - mThickness; break;
            default: break;
        }
        float percent = getProgress();
        int alpha = (int) (0xFF * SmartSwipe.ensureBetween(percent, 0.2F, 0.8F));
        mPaint.setAlpha(alpha);
        mPath.reset();
        mPath.moveTo(mPathStart.x, mPathStart.y);
        mPath.cubicTo(mPathControl1.x, mPathControl1.y, mPathControl2.x, mPathControl2.y, mPathControl.x, mPathControl.y);
        mPath.cubicTo(mPathControl3.x, mPathControl3.y, mPathControl4.x, mPathControl4.y, mPathEnd.x, mPathEnd.y);
        canvas.drawPath(mPath, mPaint);
        drawArrow(canvas, mPaintArrow, mThickness, percent);
    }

    /**
     * draw an arrow by default, subclass can draw anything else
     * @param canvas canvas
     * @param paint Paint
     * @param curThickness current thickness of BezierBackConsumer
     * @param percent percent of full swipe
     */
    protected void drawArrow(Canvas canvas, Paint paint, float curThickness, float percent) {
        percent = SmartSwipe.ensureBetween(percent, 0F, 1F);
        float startX, startY, middleX, middleY, endX, endY;
        float arrowAddition = percent < 0.5 ? 0 : (percent - 0.5f) * mArrowSize * 2;
        float offset = curThickness / 2;
        switch (mDirection) {
            case DIRECTION_LEFT:
            case DIRECTION_RIGHT:
                boolean left = mDirection == DIRECTION_LEFT;
                middleX = left ? offset : mWidth - offset;
                middleY = mPathControl.y;
                startX = endX = middleX + arrowAddition * (left ? 1 : -1);
                startY = mPathControl.y - mArrowSize;
                endY = mPathControl.y + mArrowSize;
                break;
            case DIRECTION_TOP:
            case DIRECTION_BOTTOM:
                boolean top = mDirection == DIRECTION_TOP;
                middleY = top ? offset : mHeight - offset;
                middleX = mPathControl.x;
                startY = endY = middleY + arrowAddition * (top ? 1 : -1);
                startX = mPathControl.x - mArrowSize;
                endX = mPathControl.x + mArrowSize;
                break;
            default:
                return;
        }
        mPaintArrow.setAlpha((int) (0xFF * percent));
        mPathArrow.reset();
        mPathArrow.moveTo(startX, startY);
        mPathArrow.lineTo(middleX, middleY);
        mPathArrow.lineTo(endX, endY);
        canvas.drawPath(mPathArrow, paint);
    }

    public BezierBackConsumer setSize(int size) {
        this.mSize = size;
        return this;
    }

    protected int getSize() {
        return mSize;
    }

    public int getColor() {
        return mColor;
    }

    public BezierBackConsumer setColor(int color) {
        this.mColor = color;
        mPaint.setColor(color);
        return this;
    }

    public int getArrowColor() {
        return mArrowColor;
    }

    public BezierBackConsumer setArrowColor(int color) {
        this.mArrowColor = color;
        mPaintArrow.setColor(color);
        return this;
    }

    public boolean isCenter() {
        return mCenter;
    }

    public BezierBackConsumer setCenter(boolean center) {
        this.mCenter = center;
        return this;
    }
}

它的拖拽方向可以代码设置,演示图中只演示了左右两个方向。

代码实现如下:

    SmartSwipe.wrap(this)
            .addConsumer(new BezierBackConsumer())
            .enableAllDirections()
            .addListener(new SimpleSwipeListener(){

                @Override
                public void onSwipeOpened(SmartSwipeWrapper wrapper, SwipeConsumer consumer, int direction) {
                    //关闭当前界面
                    ImageViewerActivity.this.finish();
                }
    });

[本章完...]

相关文章

网友评论

    本文标题:侧滑效果[第十一篇]:侧滑框架SmartSwipe之贝塞尔曲线返

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