分享

Android 自定义 View

 一楠tech 2017-12-05

项目介绍:

介绍
升级MIUI8之后,小米自带的天气应用晴天的时候动画效果很赞。然后就捣鼓了几下写了个简易的demo。
我们先来看看实现后的效果:
正常模式:
img1
View跟随手机摇晃后移动:
img2

分析动画分解
  • 飞翔的鸟群
  • 树的枝干会倾斜15~30度,并在达到倾斜的最大角度后抛出树叶,等树叶消失后,回到最初位置。
  • 树叶每次抛出角度不固定,并且在下落一定距离后渐渐消失。
  • 左右摇晃手机,背景的山会随着手机移动。
实现
(1) 下载app,然后将其后缀名改为zip解压获取我们需要的资源图片:
img3
(2) 实现鸟群动画
思路:通过解压后得到的素材可以发现鸟扇动翅膀的实现类似于帧动画,鸟群的运动轨迹是曲线,我们可以使用贝塞尔曲线,为了能够实时移动鸟群,我们需要获取贝塞尔曲线上面的点坐标,这里我是使用函数来计算出点坐标,也可以用PathMeasure来实现。综上,用ValueAnimator实现实时计算鸟群移动点坐标,设定一个计数器,用来更新鸟的Bitmap实现帧动画效果。
核心代码
[Java] 查看源文件 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
   isDrawBirds = true;[/size][/backcolor]        BezierEvaluator bezierEvaluator = new BezierEvaluator(newPointF(birdControlPointX, birdControlPointY));
    final ValueAnimator anim = ValueAnimator.ofObject(bezierEvaluator,
            new PointF(birdStartPointX, birdStartPointY),
            new PointF(birdEndPointX, birdEndPointY));
    anim.setDuration(8000);
    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator valueAnimator) {
            PointF point = (PointF) valueAnimator.getAnimatedValue();
            birdMovePointX = (int) point.x;
            birdMovePointY = (int) point.y;
            ++birdTimes;
            if (birdTimes % 8 == 0){
               updatebirds(birdTimes);
            }
            invalidate();
        }
    });
    anim.setInterpolator(new LinearInterpolator());
    anim.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationRepeat(Animator animation) {
            super.onAnimationRepeat(animation);
            birdTimes = 0 ;
        }
    });
    anim.setRepeatMode(ValueAnimator.RESTART);
    anim.setRepeatCount(ValueAnimator.INFINITE);
    anim.start();
private void updatebirds(int birdTimes){
    bird = birdsList.get(birdTimes % 16);
}
(2) 树动画


思路:看到这素材就知道树是拼凑出来的。树动画的实现,通过观察可以发现是treeBallLeft,treeBallMiddle,treeBallRight,通过绕treeBranch的中心点实现。
核心代码
[Java] 查看源文件 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
valueAnimatorTree = new ValueAnimator().ofFloat(0, 15);
      valueAnimatorTree.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
          @Override
          public void onAnimationUpdate(ValueAnimator animation) {
              rotateValueTree = 360 - (float) animation.getAnimatedValue();
              invalidate();
          }
      });
      valueAnimatorTree.addPauseListener(new Animator.AnimatorPauseListener() {
          @Override
          public void onAnimationPause(Animator animation) {
              rotateValueTree = 0;
              isDrawTree = true;
              startAnimLeaf();
          }
          @Override
          public void onAnimationResume(Animator animation) {
          }
      });
      valueAnimatorTree.addListener(new AnimatorListenerAdapter() {
          @Override
          public void onAnimationRepeat(Animator animation) {
              ++timesTree;
              if (timesTree % 2 == 1)
                  valueAnimatorTree.pause();
          }
      });
      valueAnimatorTree.setDuration(2000);
      valueAnimatorTree.setRepeatMode(ValueAnimator.REVERSE);
      valueAnimatorTree.setRepeatCount(ValueAnimator.INFINITE);
      valueAnimatorTree.setInterpolator(new LinearInterpolator());
      valueAnimatorTree.start();
(3) 树叶动画
思路:树叶的初始位置,将树叶藏在treeBallMiddle里面。然后执行路径动画,执行路径动画的同时,根据getAnimatedFraction() 获取动画进行的百分比计算出树叶的旋转角度,动画到运行75%的时候执行透明动画就行了
核心代码
[Java] 查看源文件 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public void startAnimLeaf() {
      randomRotate = Math.random() * 90;
      BezierEvaluator bezierEvaluator = new BezierEvaluator(new PointF(treeControlPointX, treeControlPointY));
      final ValueAnimator anim = ValueAnimator.ofObject(bezierEvaluator,
              new PointF(treeStartPointX, treeStartPointY),
              new PointF(treeEndPointX, treeEndPointY));
      anim.setDuration(4000);
      anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
          @Override
          public void onAnimationUpdate(ValueAnimator valueAnimator) {
              PointF point = (PointF) valueAnimator.getAnimatedValue();
              moveLeafX = point.x;
              moveLeafY = point.y;
              float fraction =valueAnimator.getAnimatedFraction();
              rotateValueLeaf = 90 * fraction;
              if (fraction>=0.75 && valueAnimatorAlpha.isRunning()== false){
                  startAlpha();
              }
              invalidate();
          }
      });
      anim.setInterpolator(new LinearInterpolator());
      anim.addListener(new AnimatorListenerAdapter() {
          @Override
          public void onAnimationEnd(Animator animation) {
              isDrawTree = false;
              valueAnimatorTree.resume();
              invalidate();
          }
      });
      anim.start();
  }
  private void startAlpha(){
      valueAnimatorAlpha = ValueAnimator.ofFloat(0,1);
      valueAnimatorAlpha.setDuration(1000);
      valueAnimatorAlpha.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
          @Override
          public void onAnimationUpdate(ValueAnimator valueAnimator) {
              float fraction = (float) valueAnimator.getAnimatedValue();
              treeLeafPaint.setAlpha((int) (255 - 255 * fraction));
          }
      });
      valueAnimatorAlpha.addListener(new AnimatorListenerAdapter() {
          @Override
          public void onAnimationEnd(Animator animation) {
              treeLeafPaint = new Paint();
          }
      });
      valueAnimatorAlpha.setInterpolator(new LinearInterpolator());
      valueAnimatorAlpha.start();
  }
(4) 背景
思路:通过BitmapFactory.Option来压缩背景图片的大小,保证View的流畅性。
摇晃手机的同时,背景跟着动的实现:设置背景图片的时候,宽是屏幕宽度+maxoffsetX*2。通过implements SensorEventListener,获取摇摆手机时候晃动的百分比,然后在onDraw中调用
[Java] 查看源文件 复制代码
1
2
currentOffsetX = maxOffsetX * mProgress;
canvas.translate(currentOffsetX, 0);

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多