Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

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

$
0
0

关于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.方法:

返回值 方法名 释义
void setPath(Path path, boolean forceClosed) 关联一个Path
boolean isClosed() 是否闭合
float getLength() 获取Path的长度
boolean nextContour() 跳转到下一个轮廓
boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo) 截取片段
boolean getPosTan(float distance, float[] pos, float[] tan) 获取指定长度的位置坐标及该点切线值
boolean getMatrix(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();
    }
}

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










作者:WangRain1 发表于2017/6/7 14:31:47 原文链接
阅读:827 评论:2 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>