Android 绘制水波纹小球球

2021-03-12  本文已影响0人  带带我
1615521127828.gif
public class BezierCurvePercentView extends View {

    //外圈
    private Paint paintOutside;
    private int paintOutsideColor = Color.parseColor("#FD6F5C");
    //背景色
    private Paint paintBg;
    private int paintBgColor = Color.parseColor("#F4F4F4");
    //已使用百分比
    private Paint paintPercent;
    private int paintPercentColor = Color.parseColor("#FD6F5C");
    private Path percentPath;
    //文本
    private Paint paintText;
    private int paintTextColor = Color.parseColor("#ffffff");
    private float percent = 0.3f;

    /**
     * 波纹的长度
     */
    private int WAVE_LENGTH = 300;

    /**
     * 波纹的高度
     */
    private final static int WAVE_HEGHT = 20;
    private PorterDuffXfermode mMode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);

    private int viewWidth;
    private int viewHeight;
    private int dx;

    public BezierCurvePercentView(Context context) {
        super(context);
    }

    public BezierCurvePercentView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        paintOutside = new Paint();
        paintOutside.setAntiAlias(true);
        paintOutside.setColor(paintOutsideColor);
        paintOutside.setStrokeWidth(3f);
        paintOutside.setStyle(Paint.Style.STROKE);

        paintBg = new Paint();
        paintBg.setAntiAlias(true);
        paintBg.setColor(paintBgColor);
        paintBg.setStyle(Paint.Style.FILL);

        paintPercent = new Paint();
        paintPercent.setAntiAlias(true);
        paintPercent.setColor(paintPercentColor);
        paintPercent.setStyle(Paint.Style.FILL);
        percentPath = new Path();

        paintText = new Paint();
        paintText.setAntiAlias(true);
        paintText.setColor(paintTextColor);
        paintText.setStrokeWidth(2f);
        paintText.setTextSize(100);
        paintText.setStyle(Paint.Style.FILL);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        viewWidth = MeasureSpec.getSize(widthMeasureSpec);
        viewHeight = MeasureSpec.getSize(heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int layerId = canvas.saveLayer(0, 0, viewWidth, viewHeight, null, Canvas.ALL_SAVE_FLAG);

        canvas.drawCircle(viewWidth/2, viewHeight/2, viewWidth/2-2, paintOutside);
        canvas.drawCircle(viewWidth/2, viewHeight/2, viewWidth/2-3, paintBg);

        percentPath.reset();
        percentPath.moveTo( -WAVE_LENGTH + dx, (1-percent)*viewHeight);
        for (int i = -WAVE_LENGTH; i < getWidth() + WAVE_LENGTH; i += WAVE_LENGTH) {
            percentPath.rQuadTo(WAVE_LENGTH / 4, -WAVE_HEGHT, WAVE_LENGTH / 2, 0);
            percentPath.rQuadTo(WAVE_LENGTH / 4, WAVE_HEGHT, WAVE_LENGTH / 2, 0);
        }
        percentPath.lineTo(viewWidth, viewHeight);
        percentPath.lineTo(0, viewHeight);
        percentPath.close();

        paintPercent.setXfermode(mMode);
        canvas.drawPath(percentPath, paintPercent);

        paintPercent.setXfermode(null);

        Rect rect = new Rect();
        String textStr = (int)(percent*100) + "%";
        paintText.getTextBounds(textStr, 0, textStr.length(), rect);
        canvas.drawText(textStr, viewWidth/2 - rect.width()/2, viewHeight/2 + rect.height()/2, paintText);
        canvas.restoreToCount(layerId);
    }

    public void setPercent(float percent){
        this.percent = percent;
        ValueAnimator mValueAnimator = ValueAnimator.ofInt(0, WAVE_LENGTH);
        mValueAnimator.setDuration(2000);
        mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        // 动画插值器,也可以使用其他
        mValueAnimator.setInterpolator(new LinearInterpolator());
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                dx = ( int ) animation.getAnimatedValue();
                invalidate();
            }
        });
        mValueAnimator.start();
    }
}

二阶贝塞尔曲线的两个方法 quadTo 与 rQuadTo

path.moveTo(x, y);
quadTo(x1, y1, x2, y2);
quadTo(x3, y3, x4, y4);
此方法中的每个坐标是相对起点的坐标,即 x1-x = x2-x1 = x3-x2 = x4-x3;
path.moveTo(x, y);
rQuadTo(x1, y1, x2, y2);
rQuadTo(x3, y3, x4, y4);

此方法中的每个坐标是相对上一个点的坐标,假设起点是(0, 0),波长是100,波高度20,则:

path.moveTo(0, 0);
rQuadTo(100/4, 20,100/2, 0);
↓↓↓第二段曲线 (x,y)把上一个点看做(0, 0)即相对上一个点X位移量为1/4波长=100/4,Y减少波高度20
rQuadTo(100/4, -20, 100/2, 0);

完整曲线共5个点,如下图:
path.moveTo(起点x, 起点y);
quadTo(Ax, Ay, Bx, By);
quadTo(Cx, Cy, Dx, Dy);


二阶贝塞尔.jpg
上一篇下一篇

猜你喜欢

热点阅读