很久都没有更新博客了,之前一直忙着参加挑战杯,然后就是期末考试,再然后在室友的乱带节奏下准备找实习。现在找到了一份实习工作,老大还在给新项目打框架,让我先研究下动画,说是后面会用到,就忙里偷闲玩demo

  • 是看imooc上面的一个大神的课程-http://www.imooc.com/learn/263。讲的很nice,然后我就继续深入了一点点,完善了demo而已。

    效果图

分析

  • 首先是采用了属性动画的方式
    • 在x和y上面做手脚去变化坐标
1
2
3
4
5
6
7
PropertyValuesHolder Y, X;
//设置动画
Y = PropertyValuesHolder.ofFloat("translationY", y);
X = PropertyValuesHolder.ofFloat("translationX", x);
//添加动画集合
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(imageViewList.get(i), X, Y);
  • 然后是两个动画一起
  • 使用抖动效果(使用了BounceInterpolator)[可能gif有些看不出来]
    1
    2
    //为控件增加自由落体动画效果
    animator.setInterpolator(new BounceInterpolator());

计算坐标

我们的展开是一个半圆的扇形,那么肯定就是利用数学函数来进行计算,如图

从上面到下面,x是从最大到0,y是从0到最大
每一个点的坐标就是根据圆心角来计算

1
2
3
4
5
6
//需要扩散的角度 以180度为例
float angle = (float) (Math.PI * 180 / 180);
//计算偏移的x,y坐标
x = (float) (n * Math.sin(angle / (res.length - 1) * count));
y = (float) (n * Math.cos(angle / (res.length - 1) * count));

完整代码

  • 布局
1
2
3
4
5
6
7
8
9
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
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<ImageView
android:id="@+id/iv_h"
style="@style/ImageView"
android:src="@mipmap/h"/>
<ImageView
android:id="@+id/iv_g"
style="@style/ImageView"
android:src="@mipmap/g"/>
<ImageView
android:id="@+id/iv_f"
style="@style/ImageView"
android:src="@mipmap/f"/>
<ImageView
android:id="@+id/iv_e"
style="@style/ImageView"
android:src="@mipmap/e"/>
<ImageView
android:id="@+id/iv_d"
style="@style/ImageView"
android:src="@mipmap/d"/>
<ImageView
android:id="@+id/iv_c"
style="@style/ImageView"
android:src="@mipmap/c"/>
<ImageView
android:id="@+id/iv_b"
style="@style/ImageView"
android:src="@mipmap/b"/>
<ImageView
android:id="@+id/iv_a"
style="@style/ImageView"
android:src="@mipmap/a"/>
</RelativeLayout>
  • 抽取的属性
1
2
3
4
5
6
<style name="ImageView">
<item name="android:layout_width">50dp</item>
<item name="android:layout_height">50dp</item>
<item name="android:paddingLeft">5dp</item>
<item name="android:paddingTop">5dp</item>
</style>
  • 逻辑
1
2
3
4
5
6
7
8
9
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package com.sorgs.animtest;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.BounceInterpolator;
import android.widget.ImageView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private int[] res = {R.id.iv_a, R.id.iv_b, R.id.iv_c, R.id.iv_d, R.id.iv_e, R.id.iv_f, R.id.iv_g, R.id.iv_h};
private List<ImageView> imageViewList = new ArrayList<>();
/**
* 菜单打开或者关闭的标志
*/
private boolean flag = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
for (int re : res) {
//循环添加每个控件
ImageView imageView = (ImageView) findViewById(re);
//为每个控件添加点击事件
imageView.setOnClickListener(this);
//将每个控件添加到List中
imageViewList.add(imageView);
}
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.iv_a:
if (flag) {
startAnim();
} else {
emdAnim();
}
break;
default:
//点击其他按钮,弹出toast
Toast.makeText(getApplication(), "click" + view.getId(), Toast.LENGTH_SHORT).show();
break;
}
}
/**
* 关闭菜单动画
*/
private void emdAnim() {
for (int i = 1; i < res.length; i++) {
PropertyValuesHolder Y, X;
//X Y 都回归原点
Y = PropertyValuesHolder.ofFloat("translationY", 0);
X = PropertyValuesHolder.ofFloat("translationX", 0);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(imageViewList.get(i), X, Y);
//设置动画执行时间
animator.setDuration(500);
//每个控件之间的延时,形成每个按钮依次出现
animator.setStartDelay(i * 300);
//为控件增加自由落体动画效果
animator.setInterpolator(new BounceInterpolator());
//执行动画
animator.start();
//重置flag
flag = true;
}
}
/**
* 打开菜单动画
*/
private void startAnim() {
//扩散的距离,获取控件的高度的2倍
float x, y, n = imageViewList.get(0).getMeasuredHeight() * 2;
for (int i = 1; i < res.length; i++) {
int count = res.length - i;
//需要扩散的角度 以180度为例
float angle = (float) (Math.PI * 180 / 180);
//计算偏移的x,y坐标
x = (float) (n * Math.sin(angle / (res.length - 1) * count));
y = (float) (n * Math.cos(angle / (res.length - 1) * count));
PropertyValuesHolder Y, X;
//设置动画
Y = PropertyValuesHolder.ofFloat("translationY", y);
X = PropertyValuesHolder.ofFloat("translationX", x);
//添加动画集合
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(imageViewList.get(i), X, Y);
//设置动画执行时间
animator.setDuration(500);
//每个控件之间的延时,形成每个按钮依次出现
animator.setStartDelay(i * 300);
//为控件增加自由落体动画效果
animator.setInterpolator(new BounceInterpolator());
//执行动画
animator.start();
//重置flag
flag = false;
}
}
}