WaterView 自定义圆形水波进度

这几天不是很忙,完成了工作,利用闲暇的时间来完成一下以前不会玩的自定义动画,自定义圆形水波进度,这个以前把我难死了,死活不会。都怪自己太菜了。那么现在来看看到底难不难,真正最简单的实现方法。

先来了解下path类的基本方法。

移动起点    moveTo  移动下一次操作的起点位置
设置终点    setLastPoint    重置当前path中最后一个点位置,如果在绘制之前调用,效果和moveTo相同
连接直线    lineTo  添加上一个点到当前点之间的直线到Path
闭合路径    close   连接第一个点连接到最后一个点,形成一个闭合区域
添加内容    addRect, addRoundRect, addOval, addCircle, addPath, addArc, arcTo   添加(矩形, 圆角矩形, 椭圆, 圆, 路径, 圆弧) 到当前Path (注意addArc和arcTo的区别)
是否为空    isEmpty 判断Path是否为空
是否为矩形   isRect  判断path是否是一个矩形
替换路径    set 用新的路径替换到当前路径所有内容
偏移路径    offset  对当前路径之前的操作进行偏移(不会影响之后的操作)
贝塞尔曲线   quadTo, cubicTo 分别为二次和三次贝塞尔曲线的方法
rXxx方法  rMoveTo, rLineTo, rQuadTo, rCubicTo 不带r的方法是基于原点的坐标系(偏移量), rXxx方法是基于当前点坐标系(偏移量)
填充模式    setFillType, getFillType, isInverseFillType, toggleInverseFillType  设置,获取,判断和切换填充模式
提示方法    incReserve  提示Path还有多少个点等待加入(这个方法貌似会让Path优化存储结构)
布尔操作(API19) op  对两个Path进行布尔运算(即取交集、并集等操作)
计算边界    computeBounds   计算Path的边界
重置路径    reset, rewind   清除Path中的内容
reset不保留内部数据结构,但会保留FillType.
rewind会保留内部的数据结构,但不保留FillType
矩阵操作    transform   矩阵变换

这里我们要用的就是path里面的quadTo,二次贝塞尔曲线,二次贝塞尔曲线这个可以资料,这里重点不再这里。
http://blog.csdn.net/z82367825/article/details/51599245
canvas.clipPath();这个方法也很重要,剪切,Clip(剪切)的时机:通常理解的clip(剪切),是对已经存在的图形进行clip的。但是,在android上是对canvas(画布)上进行clip的,要在画图之前对canvas进行clip,如果画图之后再对canvas进行clip不会影响到已经画好的图形。一定要记住clip是针对canvas而非图形。
以前做圆角图片的时候用这个
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));这俩作用不一样,setXfermode这个主要是针对图片的处理。

看看这波涛汹涌的效果

水波加载动画

全部代码在下面


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Region;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

/**
 * Created by 
 */

public class WaterView extends View {

    final String TAG = this.getClass().getSimpleName();


    int h, w;//控件的宽高
    int waveHight = 50;//波浪的高度,也可以说是控制点的高度
    int waveW = 800;//波长
    int baseLine;// 基准线,可以控制水波上涨
    int halfwave;//半个波长
    int offset = 5;//偏移量,控制波浪的滚动
    int waveCount;//控件可以放多少个波长

    static boolean isStart = false;

    private Paint framePaint = new Paint();
    private Paint circlePaint = new Paint();
    int frameColor = Color.RED;
    private Path framePath = new Path();
    WaveThread mWaveThread;

    public WaterView(Context context) {
        this(context, null);
    }

    public WaterView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public WaterView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }


    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        isStart = false;
        mWaveThread = null;
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        this.h = h;
        this.w = w;
        baseLine = h;
        waveCount = w / waveW + 1;//这里必须加上1,int  3/2=1,这里就只显示一个波长,还有半个波长不显示。
        framePath.reset();

    }

    private void init() {
        framePaint.setColor(frameColor);
        framePaint.setAntiAlias(true);
        halfwave = waveW / 2;
        circlePaint.setColor(Color.BLUE);
        circlePaint.setStyle(Paint.Style.STROKE);
        circlePaint.setStrokeWidth(3);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        framePath.reset();
        framePath.addCircle(w / 2, h / 2, w / 2, Path.Direction.CW);
        canvas.clipPath(framePath, Region.Op.INTERSECT);
        canvas.drawCircle(w * 1.0f / 2, h * 1.0f / 2, h * 1.0f / 2, circlePaint);

        framePath.reset();
        framePath.moveTo(-2 * halfwave + offset, baseLine);
        for (int i = -2; i < waveCount * 2; i++) {
            if (i % 2 == 0) {
                framePath.quadTo(i * halfwave + halfwave / 2 + offset, baseLine + waveHight, i * halfwave + halfwave + offset, baseLine);
            } else {
                framePath.quadTo(i * halfwave + halfwave / 2 + offset, baseLine - waveHight, i * halfwave + halfwave + offset, baseLine);
            }
        }
        framePath.lineTo(w, h);
        framePath.lineTo(0, h);
        framePath.close();
        canvas.drawPath(framePath, framePaint);
    }

    public void start() {
        if (!isStart) {
            isStart = true;
            mWaveThread = new WaveThread();
            mWaveThread.start();
        }
    }

    public void stop() {
        isStart = false;
    }

    class WaveThread extends Thread {


        @Override
        public void run() {
            super.run();
            while (isStart) {
                offset += 15;
                if (offset >= waveW)
                    offset = offset - waveW;
                if (baseLine < 0) {
                    isStart = false;
                    Log.e(TAG, "run: ");


                }
                baseLine -= 2;
                try {
                    postInvalidate();
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

这种效果还有一种实现方式,相对麻烦点
主要就是sin函数,y = Asin(wx+b)+h ,这个公式里:w影响周期,A影响振幅,h影响y位置,b为初相。根据函数计算出两个波浪的path ,最后进行绘制,有兴趣的盆友可以研究下这个。

想了解更多,可以添加公众号

这里写图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值