365体育网址可自己小时候底记得几乎没了。光会使。

切莫知晓大家发无起这种感觉,童年的记得好像短失了。。。

这次未是充分钟动画,今天设享受的凡PathMeasure的玩法。

92年圣诞节出生,纯正90继。到目前为止也从未多可怜,但自己小时候底记忆几乎没了。少有的记得停留于四驱兄弟、光会使这片总理动画达。。。

先是我们来回顾一下小时候吧~~90后满盈之记得

就几乎哪时,“奥迪双钻,我的同伴”的音响萦绕耳畔。

徒会使

然极响的响动要——多莫克萨拉莫,闪光吧,你,光会使。

小儿连幻想着祥和会变身,今天咱们虽来用代码实现变身的率先步吧,动画绘制一个魔法阵magic_circle~~

唯有会使受到三雅魔鬼法阵

magic_circle.jpg

哈哈哈。看了仅仅会使却并未和谐画了及时三只魔法阵的,有么?

静态图片于轻,我们因此 Path 设置好路,然后又 canvas.drawPath
即可,但是静态的为太 low 了一些,我们设为它们动起来。

早就几乎何时,小学的讲义上处处都是六角形。

实现效益:

自家怀念,能够在初中的率先坏几哪考试会将到100分是免是和小学一直写是产生涉及呢?

magic_circle1.gif

下面真正的就会使出场!

职能看罢了,不会见刻画的童鞋肯定已经懵逼了,会的童鞋可以出外左拐了,因为实现实在太简单。

无非会使魔法阵

好了,在开头撸代码之前,我们先来学习一个近乎
PathMeasure。我们的只是会而者阵就是凡冲此类似的星星点点个章程撸出来的。

止会使出场阶段

PathMeasure

这个类似的 class 注释就一个版权说明,酱紫~

Copyright.png

踏马的,Google
工程师还偷懒了,注释都无写。。。幸好是看似才出一百几近执行代码,那我们不怕自己拘留吧

出场了

Public constructors

  • PathMeasure 创建一个缺损的 pathmeasure 对象
  • PathMeasure(Path path,boolean forceClosed)创建一个带来 path 参数的
    PathMeasure,forceClosed控制 path 是否自动关闭

正面图

Public methods

  • getLength() 返回时 Path 的究竟长度。
  • getMatrix(float distance, Matrix matrix, int flags)
  • getPosTan(float distance, float[] pos, float[]
    tan)获取distance长度的 point 值给 pos,point 点的正切值给 tan。
  • getSegment(float startD, float stopD, Path dst, boolean
    startWithMoveTo) 获取 path 的一个部分,即startD到 stopD
    的线条,辅助给 dst。
  • isClosed() 是否自动关闭
  • nextContour() 移动及下同样长达曲线。如果 path
    中含有不总是的线条,getLength、getPosTan等方式的会于首先长线达运行,需要采用此法子跳到第二漫漫线
  • setPath(Path path, boolean forceClosed)

大凡免是大简短,就这么几独方法,现在错过画光能而者阵来思路了么~~
连着下为便于大家了解,我们重来简单回顾一下 path 的
api,因为静态的单会如者阵是得 path 去绘制的。

着重角色

Path

方法名 作用
moveTo 移动到指定点
setLastPoint 重新设置当前 Path 的最后一个点,如果当前 Path 为空,则等同上个方法
lineTo 添加当前点到一个指定点的直线
close 连接当前点到起点,形成闭合路径
addRect、addRoundRect、addOval、addCircle、addPath、addArc、arcTo 添加各种图形
isEmpty 是否为空
isRect 是否为矩形
set 用一个新的 path 替换
offset 对当前的路径进行偏移,不会影响后续操作
quadTo、cubicTo 贝塞尔曲线
rMoveTo、rLineTo、rQuaTo、rCubicTo 带 r 的是基于当前点的偏移量,不带 r 基于坐标原点
setFillType、getFillType 设置填充模式
transform 矩阵变换

就是如此概括回顾一下吧,具体玩法可以参见 Hencoder 的 bolg【HenCoder
Android 开发进阶: 自定义 View 1-1
绘制基础】

光会使三哥们

卡通拆解

吓了,准备干活完,我们初步撸代码


第一步,绘制静态的独自会使者阵

率先绘制两只健全,然后就是当中的六角星(其实仔细看便是零星单三角形)。
且是大简单的法子,同学等动手去写的上或会见赶上一个这样的题材,就是三角形的老三个点未好取。其实挺粗略,直接以圆上取0,1/3,2/3长的接触即可,刚刚我们不是说了
PathMeasure 的方法么,用getPosTan就好实现。

汝还记这些吗

  • 吉布卡伊布利斯
  • 雅鹿里啪啪
  • 哈利路球球哈呀呀
  • 。。。

接留言和自我交流~


自我是闫大伯,一只有拘留正在只会使长大的野生程序猿

次步,让才会使阵动起来

此间我们管这动画效果分成三个阶段吧。

  • 首先品级,绘制两单全面

step_1.gif

而达到图所示,这里少单圆满是渐渐绘制出来的, 圆的 path
很爱绘制出,这里我便未开腔了,然后PathMeasure的getLength可以收获 path
总的长,getSegment可以得有点至某某点的 Path。因此一个
ValueAnimator 就得缓解从0到100%长短的历程,具体实现看后的代码。
然后问题来了,path画出来的统筹兼顾的起点于乌?怎么控制两单到开始绘制的角度不雷同。有同学也许想到了盘90°再打第二独圆满,当然这种方式是可兑现的,但是由于后面的三角也用旋转,这里我们便无须
path 画圆了,用 path 添加一个刚方形 Rect
的圆弧也是一个圆,然后我们的弧形可以操纵初步之角度,弧度。
下一场改成这样了

erroe_1.gif

WTF?角度怎么怪了,我明白设置的开头角度的呀

innerCircle.addArc(innerRect, 150, -360);
outerCircle.addArc(outerRect, 60, -360);

末尾有只大牛说若的圆变成闭环了,PathMeasure
找不交起接触,用了默认的。你拿360渡过变更成为359.9叫他非是一个闭环的无微不至就行了。

  • 第二号,两个点于圆里面弹射

step_2.gif

关押起好像还要干什么碰撞反弹之类的从业,一入高科技之旗帜,其实不是的。

轨道就是有限独三角形,怎么受简单修线就三角形走吧,而且移动的下还要不段变化长度。

恰好率先步我们之所以 ValueAnimator 来决定一个圆从0到100%之经过,

pathMeasure.getSegment(0, distance * pathMeasure.getLength(), drawPath,
true);

没完没了截取起点至*%长度的 path 赋值给drawPath。

自里是自起点开始截取,那么我们不自起点开始截取,从当下接触紧邻开截取不纵执行了邪,哈哈哈哈~so
easy

float stopD = distance * pathMeasure.getLength();
float startD = stopD – (0.5f – Math.abs(0.5f – distance)) * 200;
pathMeasure.getSegment(startD, stopD, drawPath, true);
酱紫~~

  • 其三品级绘制两个三角

step_3.gif

实质上简单只三角形就是第二步的移位轨迹,也是身为直接用第阶段的 Path
即可,然后还就此第一号同的方法就是足以实现力量。

代码实现

public class GranzortView extends View {

private Paint paint;

private Path innerCircle;//内圆 path
private Path outerCircle;//外圆 path
private Path trangle1;//第一个三角形的 Path
private Path trangle2;//第二个三角形的 Path
private Path drawPath;//用于截取路径的 Path

private PathMeasure pathMeasure;

private float mViewWidth;
private float mViewHeight;

private long duration = 3000;
private ValueAnimator valueAnimator;

private Handler mHanlder;

private float distance;//当前动画执行的百分比取值为0-1
private ValueAnimator.AnimatorUpdateListener animatorUpdateListener;
private Animator.AnimatorListener animatorListener;

private State mCurrentState = State.CIRCLE_STATE;

//三个阶段的枚举
private enum State {
    CIRCLE_STATE,
    TRANGLE_STATE,
    FINISH_STATE
}

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

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

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

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mViewWidth = w;
    mViewHeight = h;
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawColor(getResources().getColor(R.color.colorPrimary));
    canvas.save();
    canvas.translate(mViewWidth / 2, mViewHeight / 2);
    switch (mCurrentState) {
        case CIRCLE_STATE:
            drawPath.reset();
            pathMeasure.setPath(innerCircle, false);
            pathMeasure.getSegment(0, distance * pathMeasure.getLength(), drawPath, true);
            canvas.drawPath(drawPath, paint);
            pathMeasure.setPath(outerCircle, false);
            drawPath.reset();
            pathMeasure.getSegment(0, distance * pathMeasure.getLength(), drawPath, true);
            canvas.drawPath(drawPath, paint);
            break;
        case TRANGLE_STATE:
            canvas.drawPath(innerCircle, paint);
            canvas.drawPath(outerCircle, paint);
            drawPath.reset();
            pathMeasure.setPath(trangle1, false);
            float stopD = distance * pathMeasure.getLength();
            float startD = stopD - (0.5f - Math.abs(0.5f - distance)) * 200;
            pathMeasure.getSegment(startD, stopD, drawPath, true);
            canvas.drawPath(drawPath, paint);
            drawPath.reset();
            pathMeasure.setPath(trangle2, false);
            pathMeasure.getSegment(startD, stopD, drawPath, true);
            canvas.drawPath(drawPath, paint);
            break;
        case FINISH_STATE:
            canvas.drawPath(innerCircle, paint);
            canvas.drawPath(outerCircle, paint);
            drawPath.reset();
            pathMeasure.setPath(trangle1, false);
            pathMeasure.getSegment(0, distance * pathMeasure.getLength(), drawPath, true);
            canvas.drawPath(drawPath, paint);
            drawPath.reset();
            pathMeasure.setPath(trangle2, false);
            pathMeasure.getSegment(0, distance * pathMeasure.getLength(), drawPath, true);
            canvas.drawPath(drawPath, paint);
            break;

    }

    canvas.restore();

}

private void init() {

    initPaint();

    initPath();

    initHandler();

    initAnimatorListener();

    initAnimator();

    mCurrentState = State.CIRCLE_STATE;
    valueAnimator.start();

}

private void initHandler() {
    mHanlder = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (mCurrentState) {
                case CIRCLE_STATE:
                    mCurrentState = State.TRANGLE_STATE;
                    valueAnimator.start();
                    break;
                case TRANGLE_STATE:
                    mCurrentState = State.FINISH_STATE;
                    valueAnimator.start();
                    break;
            }
        }
    };
}

private void initAnimatorListener() {
    animatorUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            distance = (float) animation.getAnimatedValue();
            invalidate();
        }
    };

    animatorListener = new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {
            Log.e("star:",mCurrentState+"_");
        }

        @Override
        public void onAnimationEnd(Animator animation) {
            Log.e("end:",mCurrentState+"_");
            mHanlder.sendEmptyMessage(0);
        }

        @Override
        public void onAnimationCancel(Animator animation) {

        }

        @Override
        public void onAnimationRepeat(Animator animation) {

        }
    };
}

private void initAnimator() {
    valueAnimator = ValueAnimator.ofFloat(0, 1).setDuration(duration);

    valueAnimator.addUpdateListener(animatorUpdateListener);

    valueAnimator.addListener(animatorListener);
}

private void initPath() {
    innerCircle = new Path();
    outerCircle = new Path();
    trangle1 = new Path();
    trangle2 = new Path();
    drawPath = new Path();

    pathMeasure = new PathMeasure();

    RectF innerRect = new RectF(-220, -220, 220, 220);
    RectF outerRect = new RectF(-280, -280, 280, 280);
    innerCircle.addArc(innerRect, 150, -359.9F);     // 不能取360f,否则可能造成测量到的值不准确
    outerCircle.addArc(outerRect, 60, -359.9F);

    pathMeasure.setPath(innerCircle, false);

    float[] pos = new float[2];
    pathMeasure.getPosTan(0, pos, null);        // 获取开始位置的坐标
    trangle1.moveTo(pos[0], pos[1]);
    pathMeasure.getPosTan((1f / 3f) * pathMeasure.getLength(), pos, null);
    System.out.println("pos : " + pos[0] + "  " + pos[1]);

    trangle1.lineTo(pos[0], pos[1]);
    pathMeasure.getPosTan((2f / 3f) * pathMeasure.getLength(), pos, null);
    trangle1.lineTo(pos[0], pos[1]);
    trangle1.close();

    pathMeasure.getPosTan((2f / 3f) * pathMeasure.getLength(), pos, null);
    Matrix matrix = new Matrix();
    matrix.postRotate(-180);
    trangle1.transform(matrix, trangle2);
}

private void initPaint() {
    paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    paint.setColor(Color.WHITE);
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(10);
    paint.setStrokeCap(Paint.Cap.ROUND);
    paint.setStrokeJoin(Paint.Join.BEVEL);
    paint.setShadowLayer(15, 0, 0, Color.WHITE);//白色光影效果
}}

哼,光会要者阵就了,离变身成为单纯会而者仅仅差喊口号及变身动作了,加油吧,有希望的程序员。
末了,感觉365体育网址有点伙伴Moo_Night享受的仅会使者阵。

相关文章