Android杂谈(21)补坑+Path动画

来源:互联网 发布:淘宝网京东商城茅台酒 编辑:程序博客网 时间:2024/06/01 09:11

转载请注意:http://blog.csdn.net/wjzj000/article/details/59112306

本菜开源的一个自己写的Demo,希望能给Androider们有所帮助,水平有限,见谅见谅…
https://github.com/zhiaixinyang/PersonalCollect (拆解GitHub上的优秀框架于一体,全部拆离不含任何额外的库导入)
https://github.com/zhiaixinyang/MyFirstApp(Retrofit+RxJava+MVP)

写在前面

来到学校接近一周的时间算是啥也没干,这篇博客便是打响武装反抗惰性学习第一枪。

之前写过一篇博客:http://blog.csdn.net/wjzj000/article/details/53929870
是关于官方的侧滑控件DrawerLayout,它本身的用法比较简单。只是我隐隐约约记得之前留了一个坑:那个可以动的控制侧滑菜单打开关闭的按钮。
正好结合这Path动画,把这个坑填上。


填坑

上篇博客中使用的有动画效果的箭头是来自:https://github.com/ChrisRenke/DrawerArrowDrawable
的开源作品,具体的使用方式,各位看官可以移步这位大神的GitHub上,一睹傲视武林一统江湖的王者之霸气。
这里简单梳理一下源码,然后进去本次博客想记录的核心Path动画。

    public DrawerArrowDrawable(Resources resources, boolean rounded) {        this.rounded = rounded;        float density = resources.getDisplayMetrics().density;        float strokeWidthPixel = STROKE_WIDTH_DP * density;        halfStrokeWidthPixel = strokeWidthPixel / 2;        linePaint = new Paint(SUBPIXEL_TEXT_FLAG | ANTI_ALIAS_FLAG);        linePaint.setStrokeCap(rounded ? ROUND : BUTT);        linePaint.setColor(BLACK);        linePaint.setStyle(STROKE);        linePaint.setStrokeWidth(strokeWidthPixel);        int dimen = (int) (DIMEN_DP * density);        bounds = new Rect(0, 0, dimen, dimen);        Path first, second;        JoinedPath joinedA, joinedB;        // 按钮的第一条线的相关路径操作        first = new Path();        first.moveTo(5.042f, 20f);        // 三阶贝塞尔曲线:说白了就是给定四个坐标点(moveTo为起始点,rCubicTo分别代表第一个控制点,第二个控制点,结束的点),系统通过贝塞尔方程画出一个线来。        first.rCubicTo(8.125f, -16.317f, 39.753f, -27.851f, 55.49f, -2.765f);        second = new Path();        second.moveTo(60.531f, 17.235f);        second.rCubicTo(11.301f, 18.015f, -3.699f, 46.083f, -23.725f, 43.456f);        //将路径缩放到给定的屏幕密度。(让按钮大小适配屏幕)        scalePath(first, density);        scalePath(second, density);        joinedA = new JoinedPath(first, second);        //省略大量类似代码    }

从这里我们基本可以看出,作者是直接使用多个Path来完成效果。
其中通过PathMeasure每个Path上的每个点的坐标位置,然后不断的重新绘制线段。
作者通过,如下代码进行回调,请求重绘:

new DrawerLayout.SimpleDrawerListener() {     @Override public void onDrawerSlide(View drawerView, float slideOffset) {            offset = slideOffset;            if (slideOffset >= .995) {                flipped = true;                drawerArrowDrawable.setFlip(flipped);            }            //省略部分代码
public void setFlip(boolean flip) {        this.flip = flip;        invalidateSelf();}

回调产生以后,就会调用作者封装的draw方法:

private void draw(Canvas canvas) {        pathA.getPointOnLine(parameter, coordsA);        pathB.getPointOnLine(parameter, coordsB);        if (rounded) insetPointsForRoundCaps();        //coordsA当前路线的坐标,通过PathMeasure的getPosTan方法获得。        canvas.drawLine(coordsA[0], coordsA[1], coordsB[0], coordsB[1], linePaint);}

通过PathMeasure的getPosTan获取中Path的多点坐标,然后重新绘制线段。完成动态效果。

OK,关于填坑,就到这里了。因为作者的源码比较的长。所以各位看官如果感兴趣的话,可以自己移步作者的GitHub之上就查看源码。

作者继承了android.graphics.drawable.Drawable来完成这个效果:
关于Drawable的官方解释:
Drawable是“可以绘制的东西”的一般抽象。通常你会处理Drawable作为绘制东西到屏幕上检索的资源类型; Drawable类提供了一个通用的API来处理可能采取各种形式的底层视觉资源。与View不同,Drawable没有任何功能来接收事件或与用户交互。


Path动画

接下来的内容是结合ValueAnimator结合Path实现动态的Path效果。
先看一下效果:

这里写图片描述

直接上代码:

初始化Path和Paint:

paint = new Paint();paint.setColor(Color.DKGRAY);paint.setStrokeWidth(10);paint.setStyle(Paint.Style.STROKE);path = new Path();path.moveTo(50, 50);for (int i = 0; i < 4; i++) {    path.lineTo(450 - i * 50, 50 + i * 50);    path.lineTo(450 - i * 50, 450 - i * 50);    path.lineTo(50 + i * 50, 450 - i * 50);    path.lineTo(50 + i * 50, 100 + i * 50);}

setPathEffect:

        PathMeasure measure = new PathMeasure(path, false);        length = measure.getLength();        animator = ValueAnimator.ofFloat(0.0f, 1.0f);        animator.setDuration(5000);        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                float fraction = animation.getAnimatedFraction();                //这里使用了一个DashPathEffect的技巧                paint.setPathEffect(createPathEffect(length, fraction));                postInvalidate();            }        });        animator.start();private static PathEffect createPathEffect(float pathLength, float phase) {        return new DashPathEffect(new float[]{pathLength, pathLength},                pathLength - phase * pathLength); }

我们在new DashPathEffect的时候传入的间隔值就是Path的全长,因此这里是没有间断的。我们控制Path的动画,实际是控制DashPathEffect的偏移,也就是pathLength - phase * pathLength,这个值是从Path全长随动画的进度逐渐减小到0。
对应到我们的效果之上就是Path从什么都没有,然后知道全部展现。(因为此时的偏移为0)

onDraw()中很简单,就是调用drawPath:

    @Override    public void onDraw(Canvas c) {        super.onDraw(c);        c.drawPath(path, paint);     }

原理非常的简单,我们可以理解是使用了DashPathEffect的错位效果。我们都知道DashPathEffect的一般制作效果是波浪线。
而这里我们使用它的偏移属性,做到了线段追逐的效果。
因为需要动态更新效果,所以使用动画进行控制。

PS:相关源码基本都存放于我的这个开源项目之中:
https://github.com/zhiaixinyang/PersonalCollect


尾声

OK,坑到这也填的差不多了。
学习虽好,但不要贪杯。有情不必终老,暗香浮动恰好。

最后希望各位看官可以star我的GitHub,三叩九拜,满地打滚求star:
https://github.com/zhiaixinyang/PersonalCollect
https://github.com/zhiaixinyang/MyFirstApp

1 0
原创粉丝点击