Android开发笔记

一个简单的笑脸加载动画

2017-09-29  本文已影响8人  一个厨子

最近在 HenCoder 学习了扔物线大神的关于自定义控件的文章。
于是找到我司设计师。

“之前跟你说来不及做的那些效果,现在有空做了”
“好,你打开支付宝看看那个转圈的笑脸加载图吧,我觉得挺不错”
(打开支付宝...瞅...)
“...好吧...我突然想起手里还有点事”


∴做个小练习吧

本人属于愚钝不堪型,懵逼1分钟后,决定还是先把脸画出来,能不能动再说吧。

第一步.画脸

两个点,一个圆弧

private Point leftEye = new Point();
private Point rightEye = new Point();

画圆弧要用的矩形

private RectF arcRectF = new RectF();

view中心点

private Point center = new Point();      

开始测量(没有考虑mode,在用的时候直接xml中写死了高宽)

private static final double ANGLE_EYE = 35;// 眼睛Point与center的连线 和 中线的夹角,35度
...
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    setMeasuredDimension(width, height);
    initViewSize(width, height);
  }

  private void initViewSize(int width, int height) {
    center.set(width / 2, height / 2);

    int strokeWidth = width / 8;//圆弧的宽
    paint.setStrokeWidth(strokeWidth);

    // 下面开始中二几何计算
    int halfStroke = strokeWidth / 2;
    float radius = width / 2 - halfStroke;

    double cos = Math.cos(Math.PI / 180 * ANGLE_EYE);
    int y = (int) (radius * (1 - cos) + halfStroke);

    double sin = Math.sin(Math.PI / 180 * ANGLE_EYE);
    leftEye.set((int) (radius * (1 - sin) + halfStroke), y);
    rightEye.set((int) (radius * (1 + sin) + halfStroke), y);
    arcRectF.set(halfStroke, halfStroke, width - halfStroke, height - halfStroke);
  }

提笔开画

private void init(Context context) {
    paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    paint.setColor(ContextCompat.getColor(context, R.color.green));
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeCap(Paint.Cap.ROUND);
  }

 @Override protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawPoint(leftEye.x, leftEye.y, paint);
    canvas.drawPoint(rightEye.x, rightEye.y, paint);
    canvas.drawArc(arcRectF, 0, 180, false, paint);//从0度开始,扫过180度.
}

上面代码贴上去,笑脸差不多就出来了 :)

笑一个.png
第二步.动起来

怎么笑呢?我瞪大了一双程序猴眼,瞅到流泪。
哎,算了,做不了人家支付宝那么细致了。
肝个差不多的得了。
嗯 我就是这样一个喜欢拖鞋滴仁 :)

于是,我就做了个看起来大概这样子的动画:

  1. 从 :)开始,)顺时针转动,头转到6点钟位置,头不走了,身子收短到0;
  2. 化作一个点从9点钟位置开始,顺时针走,走到3点钟位置;
  3. 点从3点钟位置开始变长,最后变回:)

总共两圈,停一下下,开始重复

效果就是这样:

smiling.gif

代码:

首先
来个属性progress,进度,每100表示一圈。
用这个来做动画。

然后呢

这个表示嘴的弧形绘制,依赖两个参数:开始点(.a) & 扫过的角度(swipeAngle)。
顺时针转动时,这个.a其实是尾巴。

∴ 第一段动画,.a是从3点钟位置开始,转到了第二圈的6点钟位置,即 1又4分之一圈,progress就是125。

∴ 动画这样写

    Animator animator0 = ObjectAnimator.ofFloat(this, "progress", 125);
    animator0.setInterpolator(new LinearInterpolator());
    animator0.setDuration(2500);

onDraw里这样

@Override protected void onDraw(Canvas canvas) {
    canvas.drawPoint(leftEye.x, leftEye.y, paint);
    canvas.drawPoint(rightEye.x, rightEye.y, paint);

    float per = getSwipeAnglePercent(progress);
    canvas.drawArc(arcRectF, progress * RATIO_ANGLE_PROGRESS, per * 180, false, paint);
  }

private float getSwipeAnglePercent(float progress) {
    if (progress < 75) {//进度75之前,保持扫过的角度不变
      return 1f;
    } else {
      return (125 - progress) / 50f;//之后扫过的角度匀速变小,125的时候扫过0度
    }
  }
// 不好意思,尽是magic number,我知道两个周后我自己也看不懂

嘛淡,以后自己看不懂。
画图好了 。

image.png

后面两段动画代码都差不多。

只是
加了一个变量 mode,0表示第一段动画,1表示第二,三段动画
加了一个角度变量 float swipeAngle,用来做第三段动画。
其实不太需要,只是自己脑袋比较笨,干脆两种mode分开写。
(度数设为1,来表示点)

然后根据progress的值做判断,是否需要画眼睛。

∴ onDraw就变成了一坨:

 @Override protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    if (mode == 0) {
      float per = getSwipeAnglePercent(progress);
      if (progress < 50) {
        canvas.drawPoint(leftEye.x, leftEye.y, paint);
        canvas.drawPoint(rightEye.x, rightEye.y, paint);
      }
      canvas.drawArc(arcRectF, progress * RATIO_ANGLE_PROGRESS, per * 180, false, paint);
    } else {
      if (270 - progress * RATIO_ANGLE_PROGRESS < ANGLE_EYE) {
        canvas.drawPoint(leftEye.x, leftEye.y, paint);
      }
      if (progress * RATIO_ANGLE_PROGRESS - 270 > ANGLE_EYE) {
        canvas.drawPoint(rightEye.x, rightEye.y, paint);
      }
      canvas.drawArc(arcRectF, progress * RATIO_ANGLE_PROGRESS, swipeAngle * 1, false, paint);
    }
  }
  //哎,尽是magic number ...

第2,3段:

    /* 第二段动画:Mode = 1,以点的方式转动半周*/
    Animator animator1 = ObjectAnimator.ofFloat(this, "progress", 50, 100);
    animator1.setInterpolator(new LinearInterpolator());
    animator1.setDuration(DURATION_TIME_1);

    /* 第三段动画:Mode = 1,从点变成嘴 :)*/
    Animator animator2 = ObjectAnimator.ofFloat(this, "swipeAngle", 180);
    animator2.setInterpolator(new LinearInterpolator());
    animator2.setDuration(DURATION_TIME_2);

    /* 三段动画依次播放,结束时重置动画参数,并再次启动动画*/
    animatorSet = new AnimatorSet();
    animatorSet.playSequentially(animator0, animator1, animator2);
    animatorSet.addListener(animatorSetListener);

完整代码

菜猴一只,还望路过的大神们,多多斧正 :)

懒人偶尔也想写博客

上一篇下一篇

猜你喜欢

热点阅读