当我们写商城类的项目的时候,一般都会有加入购物车的功能,加入购物车的时候会有一些抛物线动画,具体代码如下:
实现效果如图:
思路:
难点:
PathMeasure的使用
- getLength()
- boolean getPosTan(float distance, float[] pos, float[] tan) 的理解
涉及到的知识点:
如何获取控件在屏幕中的绝对坐标
1
2
3
|
//得到父布局的起始点坐标(用于辅助计算动画开始/结束时的点的坐标)
int
[] parentLocation =
new
int
[
2
];
rl.getLocationInWindow(parentLocation);
|
如何使用贝塞尔曲线以及属性动画插值器ValueAnimator
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
|
// 四、计算中间动画的插值坐标(贝塞尔曲线)(其实就是用贝塞尔曲线来完成起终点的过程)
//开始绘制贝塞尔曲线
Path path =
new
Path();
//移动到起始点(贝塞尔曲线的起点)
path.moveTo(startX, startY);
//使用二次萨贝尔曲线:注意第一个起始坐标越大,贝塞尔曲线的横向距离就会越大,一般按照下面的式子取即可
path.quadTo((startX + toX) /
2
, startY, toX, toY);
//mPathMeasure用来计算贝塞尔曲线的曲线长度和贝塞尔曲线中间插值的坐标,
// 如果是true,path会形成一个闭环
mPathMeasure =
new
PathMeasure(path,
false
);
//★★★属性动画实现(从0到贝塞尔曲线的长度之间进行插值计算,获取中间过程的距离值)
ValueAnimator valueAnimator = ValueAnimator.ofFloat(
0
, mPathMeasure.getLength());
valueAnimator.setDuration(
1000
);
// 匀速线性插值器
valueAnimator.setInterpolator(
new
LinearInterpolator());
valueAnimator.addUpdateListener(
new
ValueAnimator.AnimatorUpdateListener() {
@Override
public
void
onAnimationUpdate(ValueAnimator animation) {
// 当插值计算进行时,获取中间的每个值,
// 这里这个值是中间过程中的曲线长度(下面根据这个值来得出中间点的坐标值)
float
value = (Float) animation.getAnimatedValue();
// ★★★★★获取当前点坐标封装到mCurrentPosition
// boolean getPosTan(float distance, float[] pos, float[] tan) :
// 传入一个距离distance(0<=distance<=getLength()),然后会计算当前距
// 离的坐标点和切线,pos会自动填充上坐标,这个方法很重要。
mPathMeasure.getPosTan(value, mCurrentPosition,
null
);
//mCurrentPosition此时就是中间距离点的坐标值
// 移动的商品图片(动画图片)的坐标设置为该中间点的坐标
goods.setTranslationX(mCurrentPosition[
0
]);
goods.setTranslationY(mCurrentPosition[
1
]);
}
});
// 五、 开始执行动画
valueAnimator.start();
|
所有代码:
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
|
package
cn.c.com.beziercurveanimater;
import
android.animation.Animator;
import
android.animation.ValueAnimator;
import
android.graphics.Bitmap;
import
android.graphics.BitmapFactory;
import
android.graphics.Path;
import
android.graphics.PathMeasure;
import
android.os.Bundle;
import
android.support.v7.app.AppCompatActivity;
import
android.support.v7.widget.LinearLayoutManager;
import
android.support.v7.widget.RecyclerView;
import
android.view.LayoutInflater;
import
android.view.View;
import
android.view.ViewGroup;
import
android.view.animation.LinearInterpolator;
import
android.widget.ImageView;
import
android.widget.RelativeLayout;
import
android.widget.TextView;
import
java.util.ArrayList;
public
class
MainActivity
extends
AppCompatActivity {
private
RecyclerView mRecyclerView;
private
ImageView cart;
private
ArrayList<Bitmap> bitmapList =
new
ArrayList<>();
private
RelativeLayout rl;
private
PathMeasure mPathMeasure;
/**
* 贝塞尔曲线中间过程的点的坐标
*/
private
float
[] mCurrentPosition =
new
float
[
2
];
private
TextView count;
private
int
i =
0
;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initImg();
MyAdapter myAdapter =
new
MyAdapter(bitmapList);
mRecyclerView.setAdapter(myAdapter);
mRecyclerView.setLayoutManager(
new
LinearLayoutManager(MainActivity.
this
));
}
private
void
initImg() {
bitmapList.add(BitmapFactory.decodeResource(getResources(), R.drawable.coin));
bitmapList.add(BitmapFactory.decodeResource(getResources(), R.drawable.coin1));
bitmapList.add(BitmapFactory.decodeResource(getResources(), R.drawable.coin91));
}
private
void
initView() {
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
cart = (ImageView) findViewById(R.id.cart);
rl = (RelativeLayout) findViewById(R.id.rl);
count = (TextView) findViewById(R.id.count);
}
class
MyAdapter
extends
RecyclerView.Adapter<MyVH> {
private
ArrayList<Bitmap> bitmapList;
public
MyAdapter(ArrayList<Bitmap> bitmapList) {
this
.bitmapList = bitmapList;
}
@Override
public
MyVH onCreateViewHolder(ViewGroup parent,
int
viewType) {
LayoutInflater inflater = LayoutInflater.from(MainActivity.
this
);
View itemView = inflater.inflate(R.layout.item, parent,
false
);
MyVH myVH =
new
MyVH(itemView);
return
myVH;
}
@Override
public
void
onBindViewHolder(
final
MyVH holder,
final
int
position) {
holder.iv.setImageBitmap(bitmapList.get(position));
holder.buy.setOnClickListener(
new
View.OnClickListener() {
@Override
public
void
onClick(View v) {
addCart(holder.iv);
}
});
}
@Override
public
int
getItemCount() {
return
bitmapList.size();
}
}
/**
* ★★★★★把商品添加到购物车的动画效果★★★★★
* @param iv
*/
private
void
addCart( ImageView iv) {
// 一、创造出执行动画的主题---imageview
//代码new一个imageview,图片资源是上面的imageview的图片
// (这个图片就是执行动画的图片,从开始位置出发,经过一个抛物线(贝塞尔曲线),移动到购物车里)
final
ImageView goods =
new
ImageView(MainActivity.
this
);
goods.setImageDrawable(iv.getDrawable());
// 一、创造出执行动画的主题---imageview
//代码new一个imageview,图片资源是上面的imageview的图片
// (这个图片就是执行动画的图片,从开始位置出发,经过一个抛物线(贝塞尔曲线),移动到购物车里)
final
ImageView goods =
new
ImageView(MainActivity.
this
);
goods.setImageDrawable(iv.getDrawable());
RelativeLayout.LayoutParams params =
new
RelativeLayout.LayoutParams(
100
,
100
);
rl.addView(goods, params);
// 二、计算动画开始/结束点的坐标的准备工作
//得到父布局的起始点坐标(用于辅助计算动画开始/结束时的点的坐标)
int
[] parentLocation =
new
int
[
2
];
&;padding:0px 0px 0px 5px;background:rgb(255,255,255);border-left:3px solid rgb(108,226,108);width:640px;font-size:14px;clear:both;border-top:0px;border-right:0px;border-bottom:0px;float:none;height:auto;vertical-align:baseline;font-family:Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace;min-height:auto;color:#000000;">rl.addView(goods, params);
|