Android自定义view --Path 的高级用法之-搜索按钮动画

关于Path之前写的也很多了,例如path绘制线,path绘制一阶,二阶和三阶贝塞尔路径,这些都是path的基本用法。今天我要带大家看的是Path 的高级用法,先上图,再吹。

效果大致是这样的。看着是不是挺好。话不多说,切入正题:

既然今天要谈Path的高级用法,那就先来讲一讲(Path -- 中文 )就是“路径”既然是路径,从我们面向对象的想法的话,我们就容易想到 路径 的长度,路径的某一点等。想到这里我们就引出今天 的主要 类--------PathMeasure字面意思很容易理解--翻译成 路径测量对这就是我们用来测量路径的类。既然是一个类,我们就要看他集体有哪些方法和属性

1.构造方法:

 

方法名释义
PathMeasure()创建一个空的PathMeasure
PathMeasure(Path path, boolean forceClosed)创建 PathMeasure 并关联一个指定的Path(Path需要已经创建完成)。

一个是有参数,一个无参数。

无参数就很容易理解就是直接创建对象,那有参数呢?

PathMeasure(Path path, boolean forceClosed) ;第一个参数 Path  咿 !这不就是我们的Path 了吗。对既然是测量类,那就是要确定需要测量的那个路径,那第二个参数呢?

第二个参数是用来确保 Path 闭合,如果设置为 true, 则不论之前Path是否闭合,都会自动闭合该 Path(如果Path可以闭合的话)。

2.方法:

 

返回值方法名释义
voidsetPath(Path path, boolean forceClosed)关联一个Path
booleanisClosed()是否闭合
floatgetLength()获取Path的长度
booleannextContour()跳转到下一个轮廓
booleangetSegment(float startD, float stopD, Path dst, boolean startWithMoveTo)截取片段
booleangetPosTan(float distance, float[] pos, float[] tan)获取指定长度的位置坐标及该点切线值
booleangetMatrix(float distance, Matrix matrix, int flags)获取指定长度的位置坐标及该点Matrix

这方法还挺多,都是干啥的呢?就找几个重要的,常用的讲讲:

第一个那就是 setPath(Path path, boolean forceClosed)

这方法一看就知道设置path 路径的,就是如果我们创建 PathMeasure,时用的是无参的构造方法时 ,这时候就要用此方法,告诉PathMeasure 当前需要测量的是哪一个path路径。(个人喜欢用无参,比较灵活)。

第二个那就是getLength(),很容易理解就是 获得 path 的总长度。

第三个:getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo),这个方法非常重要,截取片段,截取的结果就是,我们的path路径。参数也很好理解。第一个是开始的距离,第二个是结束的距离(相对于起点==既然是起点,我们怎么找他们的起点呢,其实就是我们绘制图画笔开始的哪一点)。第三个参数就是返回的路径。第四个参数起始点是否使用 moveTo 用于保证截取的 Path 第一个点位置不变。

第四个:getPosTan(float distance, float[] pos, float[] tan),这个也是非常重要的,为什么呢?听我解释一下他的参数就知道了。第一个参数是距离(相对于绘制起点的路径距离),第二个参数是距离起点的坐标点,第三个参数返回的是正玄函数tan@角度。

对这些参数了解之后下面就来讲解我们今天的例子:

首先我们先来个简单的:例如

如图这样的分析过程:

1.首先绘制一个圆(蓝色的),从45度开始绘制,注意圆的起点。

2.同圆心绘制大圆(辅助圆)用来辅助绘制蓝色的线。

3.通过getPosTan(float distance, float[] pos, float[] tan)方法得到两个圆的终点的坐标。

4.利用lineTo(x,y)绘制线。就得到我们的搜索图形了。

5.接下来就是实时 截取片段。getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo),截取从距离0到getlength();这样就产生了一个动态的效果了。

看代码:

关于画笔,canvas画布,valueanimator动画,这些请看之前的博客,都有详细讲解。

public class MySearch extends View {
    Paint paint;
    Path searchPath; //搜索的圆
    Path ciclePath; //外圆
    //获得宽高
    int w;
    int h;
    //这是保存截取时,返回的坐标点
    float serpos[];
    float cicpos[];
    //测量 path 的类
    PathMeasure measure;
    //动画产生的实时数据
    float value;
    public MySearch(Context context) {
        this(context,null);
    }

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

    public MySearch(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //获得屏幕的宽高
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        w = wm.getDefaultDisplay().getWidth();
        h = wm.getDefaultDisplay().getHeight();
        //初始化数据
        serpos = new float[2];
        cicpos = new float[2];
        //画笔
        paint = new Paint();
        paint.setStyle(Paint.Style.STROKE);
        paint.setDither(true);
        paint.setStrokeWidth(6);
        paint.setAntiAlias(true);
        //初始化路径
        initPath();
        //初始化动画
        initAnimator();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //移动画布的远点到屏幕中心
        canvas.translate(w/2,h/5);
        paint.setColor(Color.BLUE);
        //这是截取方法返回的路径
        Path dra = new Path();
        //解除硬件加速,不然没效果
        dra.reset();
        dra.lineTo(0,0);
        //设置当前需要测量的path
        measure.setPath(searchPath,false);
        //开始截取
        boolean s = measure.getSegment(measure.getLength()*value,measure.getLength(),dra,true);
        //绘制路径
        canvas.drawPath(dra,paint);
    }

    /**
     * 初始化路径
     */
    public void initPath(){
        paint.setColor(Color.BLUE);
        //搜索的圆
        searchPath = new Path();
        RectF rectF = new RectF(-50,-50,50,50);
        searchPath.addArc(rectF,45,359.9f);
        //辅助圆
        ciclePath = new Path();
        RectF rectF1 = new RectF(-100,-100,100,100);
        ciclePath.addArc(rectF1,45,359.9f);
        //测量类
        measure = new PathMeasure();
        measure.setPath(searchPath,false);
        //获取坐标
        measure.getPosTan(0,serpos,null);
        measure.setPath(ciclePath,false);
        //获取坐标
        measure.getPosTan(0,cicpos,null);
        //根据两点坐标绘制线
        searchPath.lineTo(cicpos[0],cicpos[1]);
    }

    /**
     * 初始化动画
     */
    public void initAnimator(){

        ValueAnimator animator = ValueAnimator.ofFloat(0,1);
        animator.setDuration(2600);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                value = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animator.start();
    }
}

第一个图大家学会了,去练习一下吧!

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WangRain1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值