1,上周我们实现了简单的三阶贝塞尔曲线效果实例,今天是使用二阶贝塞尔曲线加动画实现的加入购物车效果,在码代码过程中出现了些问题,过一下和大家来探讨探讨,先看一下效果图
2,从上面的效果来看我们基本上可以把功能拆分为两个动画效果:+号图片按照曲线掉下(曲线的轨迹就是一个简单的贝塞尔曲线)、购物车图标从缩小到放大。知道了实现的原理我们开始我们功能的实现
- 实现基本基本布局、RecyclerView展示数据
从上面的效果我们可以得到,我们的布局是一个简单的RecyclerView和下面的RelativeLayout,布局文件如下:
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
|
<?xml version=
"1.0"
encoding=
"utf-8"
?>
<RelativeLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
xmlns:tools=
"http://schemas.android.com/tools"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:id=
"@+id/main_layout"
tools:context=
"com.qianmo.beziershopcart.MainActivity"
>
<android.support.v7.widget.RecyclerView
android:id=
"@+id/recycler"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
>
</android.support.v7.widget.RecyclerView>
<LinearLayout
android:id=
"@+id/shopping_cart_bottom"
android:layout_width=
"match_parent"
android:layout_height=
"50dp"
android:layout_alignParentBottom=
"true"
android:background=
"#fd383838"
android:orientation=
"horizontal"
>
</LinearLayout>
<FrameLayout
android:id=
"@+id/shopping_cart_layout"
android:layout_width=
"60dp"
android:layout_height=
"60dp"
android:layout_alignParentBottom=
"true"
android:layout_marginBottom=
"5dp"
android:layout_marginLeft=
"35dp"
android:background=
"@drawable/circle"
android:clickable=
"true"
>
<ImageView
android:id=
"@+id/shopping_cart"
android:layout_width=
"35dp"
android:layout_height=
"35dp"
android:layout_gravity=
"center"
android:src=
"@mipmap/ic_shopping_cart_white_24dp"
/>
</FrameLayout>
</RelativeLayout>
|
添加Shop实体类、添加RecyclerView的Adapter
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
|
package
com.qianmo.beziershopcart;
/**
* Created by wangjitao on 2017/4/10 0010.
* E-Mail:543441727@qq.com
*/
public
class
ShopBean {
private
String title;
private
String price;
private
int
count;
public
ShopBean(String title, String price,
int
count) {
this
.title = title;
this
.price = price;
this
.count = count;
}
public
String getTitle() {
return
title;
}
public
void
setTitle(String title) {
this
.title = title;
}
public
String getPrice() {
return
price;
}
public
void
setPrice(String price) {
this
.price = price;
}
public
int
getCount() {
return
count;
}
public
void
setCount(
int
count) {
this
.count = 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
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
|
package
com.qianmo.beziershopcart;
import
android.content.Context;
import
android.support.v7.widget.RecyclerView;
import
android.view.LayoutInflater;
import
android.view.View;
import
android.view.ViewGroup;
import
android.widget.ImageView;
import
android.widget.TextView;
import
android.widget.Toast;
import
java.util.List;
/**
* Created by Administrator on 2017/4/10 0010.
* E-Mail:543441727@qq.com
*/
public
class
MyAdapter
extends
RecyclerView.Adapter<MyAdapter.ViewHolder> {
private
List<ShopBean> datas;
private
Context mContext;
private
ShopOnClickListtener mShopOnClickListtener;
public
MyAdapter(List<ShopBean> datas, Context mContext) {
this
.datas = datas;
this
.mContext = mContext;
}
@Override
public
MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int
viewType) {
return
new
ViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_shop_menu, parent,
false
));
}
@Override
public
void
onBindViewHolder(MyAdapter.ViewHolder holder,
final
int
position) {
holder.shop_name.setText(datas.get(position).getTitle());
holder.shop_price.setText(datas.get(position).getPrice());
holder.count.setText(datas.get(position).getCount() +
""
);
holder.ic_add.setOnClickListener(
new
View.OnClickListener() {
@Override
public
void
onClick(View v) {
if
(mShopOnClickListtener !=
null
) {
mShopOnClickListtener.add(v, position);
}
}
});
holder.ic_reduce.setOnClickListener(
new
View.OnClickListener() {
@Override
public
void
onClick(View v) {
if
(mShopOnClickListtener !=
null
) {
mShopOnClickListtener.remove(v, position);
}
}
});
}
@Override
public
int
getItemCount() {
return
datas ==
null
?
0
: datas.size();
}
public
class
ViewHolder
extends
RecyclerView.ViewHolder {
TextView shop_name;
TextView shop_price;
TextView count;
ImageView ic_add;
ImageView ic_reduce;
public
ViewHolder(View itemView) {
super
(itemView);
shop_name = (TextView) itemView.findViewById(R.id.tv_title);
shop_price = (TextView) itemView.findViewById(R.id.tv_price);
count = (TextView) itemView.findViewById(R.id.tv_count);
ic_add = (ImageView) itemView.findViewById(R.id.iv_add);
ic_reduce = (ImageView) itemView.findViewById(R.id.iv_remove);
}
}
public
ShopOnClickListtener getShopOnClickListtener() {
return
mShopOnClickListtener;
}
public
void
setShopOnClickListtener(ShopOnClickListtener mShopOnClickListtener) {
this
.mShopOnClickListtener = mShopOnClickListtener;
}
public
interface
ShopOnClickListtener {
void
add(View view,
int
position);
void
remove(View view,
int
position);
}
}
|
在Activity中简单的添加数据
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
|
package
com.qianmo.beziershopcart;
import
android.animation.Animator;
import
android.animation.AnimatorSet;
import
android.animation.ObjectAnimator;
import
android.animation.ValueAnimator;
import
android.content.Context;
import
android.graphics.Point;
import
android.graphics.PointF;
import
android.support.v4.content.ContextCompat;
import
android.support.v7.app.AppCompatActivity;
import
android.os.Bundle;
import
android.support.v7.widget.LinearLayoutManager;
import
android.support.v7.widget.RecyclerView;
import
android.util.Log;
import
android.view.View;
import
android.view.Window;
import
android.view.WindowManager;
import
android.view.animation.AccelerateInterpolator;
import
android.widget.ImageView;
import
android.widget.LinearLayout;
import
android.widget.RelativeLayout;
import
java.util.ArrayList;
import
java.util.List;
public
class
MainActivity
extends
AppCompatActivity
implements
MyAdapter.ShopOnClickListtener {
private
Context mContext = MainActivity.
this
;
private
RelativeLayout main_layout;
private
RecyclerView mRecyclerView;
private
ImageView mImageViewShopCat;
private
List<ShopBean> datas;
private
MyAdapter myAdapter;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private
void
initView() {
mRecyclerView = (RecyclerView) findViewById(R.id.recycler);
mImageViewShopCat = (ImageView) findViewById(R.id.shopping_cart);
main_layout = (RelativeLayout) findViewById(R.id.main_layout);
initData();
}
private
void
initData() {
datas =
new
ArrayList<>();
datas.add(
new
ShopBean(
"面包"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"蛋挞"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"牛奶"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"肠粉"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"绿茶饼"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"花卷"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"包子"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"粥"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"炒饭"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"炒米粉"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"炒粿条"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"炒牛河"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"炒菜"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"淋菜"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"川菜"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"湘菜"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"粤菜"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"赣菜"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"东北菜"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"淋菜"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"川菜"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"湘菜"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"粤菜"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"赣菜"
,
"1.00"
,
10
));
datas.add(
new
ShopBean(
"东北菜"
,
"1.00"
,
10
));
mRecyclerView.setLayoutManager(
new
LinearLayoutManager(mContext));
mRecyclerView.addItemDecoration(
new
RecyclerViewDivider(mContext, LinearLayoutManager.VERTICAL,
50
, ContextCompat.getColor(mContext, R.color.colorAccent)));
myAdapter =
new
MyAdapter(datas, mContext);
mRecyclerView.setAdapter(myAdapter);
myAdapter.setShopOnClickListtener(
this
);
}
@Override
public
void
add(
final
View view,
int
position) {
Toast.makeText(mContext,
"加"
, Toast.LENGTH_SHORT).show();
}
@Override
public
void
remove(View view,
int
position) {
Toast.makeText(mContext,
"减"
, Toast.LENGTH_SHORT).show();
}
}
|
看一下我们的效果:
OK,大致的展示效果基本上是实现了
- 使用加入购物车效果
下面我们来实现贝塞尔曲线效果,首先获取两个数据点:一个是每次点击“+”号的坐标位置、一个是下面红色的购物车图标。控制点我打算取开始点的Y坐标和结束点的X坐标,那么怎么获取当前控件相对于整个屏幕的坐标呢,这里View里面有一个getLocationInWindow()方法(这里要留心一下这个方法),然后不了解的同学可以搜索一下view.getLocationInWindow(int[] location)和view.getLocationOnScreen(int[] location),方法的区别,这里我从网上偷了了一个图,如下:
1
2
|
getLocationInWindow是以B为原点的C的坐标
getLocationOnScreen以A为原点
|
ok,这样我们看一下我们的贝塞尔三个坐标的初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
@Override
public
void
add(
final
View view,
int
position) {
//贝塞尔起始数据点
int
[] startPosition =
new
int
[
2
];
//贝塞尔结束数据点
int
[] endPosition =
new
int
[
2
];
//控制点
int
[] recyclerPosition =
new
int
[
2
];
view.getLocationInWindow(startPosition);
mImageViewShopCat.getLocationInWindow(endPosition);
PointF startF =
new
PointF();
PointF endF =
new
PointF();
PointF controllF =
new
PointF();
startF.x = startPosition[
0
];
startF.y = startPosition[
1
] ;
endF.x = endPosition[
0
];
endF.y = endPosition[
1
];
controllF.y = startF.y;
}
|
继续,自定义差值器,我们按照贝塞尔的三阶公式来套,上一篇详细的介绍过了就不在废话了,这里不懂的话建议你去看一下我的上一篇博客,里面有详细的介绍
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
|
package
com.qianmo.beziershopcart;
import
android.animation.TypeEvaluator;
import
android.graphics.PointF;
/**
* Created by Administrator on 2017/4/10 0010.
* E-Mail:543441727@qq.com
*/
public
class
BezierTypeEvaluator
implements
TypeEvaluator<PointF> {
private
PointF mControllPoint;
public
BezierTypeEvaluator(PointF mControllPoint) {
this
.mControllPoint = mControllPoint;
}
@Override
public
PointF evaluate(
float
fraction, PointF startValue, PointF endValue) {
PointF pointCur =
new
PointF();
pointCur.x = (
1
- fraction) * (
1
- fraction) * startValue.x +
2
* fraction * (
1
- fraction) * mControllPoint.x + fraction * fraction * endValue.x;
pointCur.y = (
1
- fraction) * (
1
- fraction) * startValue.y +
2
* fraction * (
1
- fraction) * mControllPoint.y + fraction * fraction * endValue.y;
return
pointCur;
}
}
|
开启动画自动调用
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
|
@Override
public
void
add(
final
View view,
int
position) {
//贝塞尔起始数据点
int
[] startPosition =
new
int
[
2
];
//贝塞尔结束数据点
int
[] endPosition =
new
int
[
2
];
view.getLocationInWindow(startPosition);
mImageViewShopCat.getLocationInWindow(endPosition);
PointF startF =
new
PointF();
PointF endF =
new
PointF();
PointF controllF =
new
PointF();
startF.x = startPosition[
0
];
startF.y = startPosition[
1
] ;
endF.x = endPosition[
0
];
endF.y = endPosition[
1
];
controllF.x = endF.x;
controllF.y = startF.y;
ValueAnimator valueAnimator = ValueAnimator.ofObject(
new
BezierTypeEvaluator(controllF), startF, endF);
valueAnimator.addUpdateListener(
new
ValueAnimator.AnimatorUpdateListener() {
@Override
public
void
onAnimationUpdate(ValueAnimator animation) {
PointF pointF = (PointF) animation.getAnimatedValue();
view.setX(pointF.x);
view.setY(pointF.y);
// Log.i("wangjtiao", "viewF:" + view.getX() + "," + view.getY());
}
});
valueAnimator .setDuration(
800
);
valueAnimator .start();
}
|
按照我们的思路,这个功能基本上是实现了,感觉很简单,又可以多了些时间去打两把王者农药了,看一下我们的效果图:
呃!!!我的动画呢??? ,看一下我们打印动画轨迹的效果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
04
-
10
03
:
55
:
37.271
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
899.42816
,
608.6747
04
-
10
03
:
55
:
37.306
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
841.05066
,
615.05853
04
-
10
03
:
55
:
37.369
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
700.9506
,
644.04346
04
-
10
03
:
55
:
37.399
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
626.5742
,
669.1555
04
-
10
03
:
55
:
37.427
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
552.1316
,
703.05035
04
-
10
03
:
55
:
37.474
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
477.8907
,
747.9864
04
-
10
03
:
55
:
37.502
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
410.36102
,
801.63885
04
-
10
03
:
55
:
37.528
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
348.99896
,
864.93835
04
-
10
03
:
55
:
37.549
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
320.21585
,
901.0647
04
-
10
03
:
55
:
37.601
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
247.92773
,
1019.08307
04
-
10
03
:
55
:
37.629
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
210.69424
,
1104.1696
04
-
10
03
:
55
:
37.650
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
194.71275
,
1149.3108
04
-
10
03
:
55
:
37.672
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
180.81482
,
1194.8556
04
-
10
03
:
55
:
37.716
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
150.94038
,
1327.2924
04
-
10
03
:
55
:
37.744
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
138.87828
,
1409.5398
04
-
10
03
:
55
:
37.771
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
134.5641
,
1449.0864
04
-
10
03
:
55
:
37.799
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
129.06772
,
1518.4921
04
-
10
03
:
55
:
37.813
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
127.390335
,
1549.7286
04
-
10
03
:
55
:
37.852
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
125.646034
,
1600.0463
04
-
10
03
:
55
:
37.873
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
125.263214
,
1620.108
04
-
10
03
:
55
:
37.902
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
125.0176
,
1646.6577
04
-
10
03
:
55
:
37.932
29510
-
29510
/com.qianmo.beziershopcart I/wangjtiao: viewF:
125.0
,
1656.0
|
view的坐标一直在改变啊!思路上没什么问题啊,想了好久,会不会是因为这是RecyclerView的item的ImageView,是不是它不能超过它父控件的距离呢?(到最后我也没搞懂为什么不显示view,如果知道的同学请告知一下),姑且算是这个问题,那我们就每次都new一个ImageView,添加到主布局中,代码如下:
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
|
@Override
public
void
add(
final
View view,
int
position) {
//贝塞尔起始数据点
int
[] startPosition =
new
int
[
2
];
//贝塞尔结束数据点
int
[] endPosition =
new
int
[
2
];
//控制点
int
[] recyclerPosition =
new
int
[
2
];
view.getLocationInWindow(startPosition);
mImageViewShopCat.getLocationInWindow(endPosition);
mRecyclerView.getLocationInWindow(recyclerPosition);
PointF startF =
new
PointF();
PointF endF =
new
PointF();
PointF controllF =
new
PointF();
startF.x = startPosition[
0
];
startF.y = startPosition[
1
];
endF.x = endPosition[
0
];
endF.y = endPosition[
1
];
controllF.x = endF.x;
controllF.y = startF.y;
Log.i(
"wangjtiao"
,
"startF:"
+ startF.x +
","
+ startF.y);
Log.i(
"wangjtiao"
,
"endF:"
+ endF.x +
","
+ endF.y);
Log.i(
"wangjtiao"
,
"ControllF:"
+ endF.x +
","
+ controllF.y);
Log.i(
"wangjtiao"
,
"ControllF:"
+ recyclerPosition[
0
] +
","
+ recyclerPosition[
1
]);
final
ImageView imageView =
new
ImageView(
this
);
main_layout.addView(imageView);
imageView.setImageResource(R.mipmap.ic_add_circle_blue_700_36dp);
imageView.getLayoutParams().width = getResources().getDimensionPixelSize(R.dimen.item_dish_circle_size);
imageView.getLayoutParams().height = getResources().getDimensionPixelSize(R.dimen.item_dish_circle_size);
imageView.setVisibility(View.VISIBLE);
imageView.setX(startF.x);
imageView.setY(startF.y);
ValueAnimator valueAnimator = ValueAnimator.ofObject(
new
BezierTypeEvaluator(controllF), startF, endF);
valueAnimator.addUpdateListener(
new
ValueAnimator.AnimatorUpdateListener() {
@Override
public
void
onAnimationUpdate(ValueAnimator animation) {
PointF pointF = (PointF) animation.getAnimatedValue();
imageView.setX(pointF.x);
imageView.setY(pointF.y);
Log.i(
"wangjtiao"
,
"viewF:"
+ view.getX() +
","
+ view.getY());
}
});
valueAnimator.setDuration(
800
);
valueAnimator.start();
}
|
效果如下:
??这又是什么鬼,两个控制点出问题了??既然控制点出问题了我们来看看我们控制点怎么得到的:view.getLocationInWindow(int[] location)和view.getLocationOnScreen(int[] location),,感觉也没什么问题啊 我们打印一下我们的贝塞尔两个数据点和一个控制点
1
2
3
|
04
-
10
02
:
45
:
33.179
32056
-
32056
/com.qianmo.beziershopcart I/wangjtiao: startF:
1014.0
,
242.0
04
-
10
02
:
45
:
33.183
32056
-
32056
/com.qianmo.beziershopcart I/wangjtiao: endF:
125.0
,
1656.0
04
-
10
02
:
45
:
33.183
32056
-
32056
/com.qianmo.beziershopcart I/wangjtiao: ControllF:
125.0
,
242.0
|
ok,这里我们看不到我们的效果,我们将view.getLocationInWindow(int[] location)替换成view.getLocationOnScreen(int[] location)
1
2
3
|
04
-
10
02
:
40
:
44.161
27735
-
27735
/com.qianmo.beziershopcart I/wangjtiao: startF:
1014.0
,
242.0
04
-
10
02
:
40
:
44.161
27735
-
27735
/com.qianmo.beziershopcart I/wangjtiao: endF:
125.0
,
1656.0
04
-
10
02
:
45
:
33.183
32056
-
32056
/com.qianmo.beziershopcart I/wangjtiao: ControllF:
125.0
,
242.0
|
???为什么两次获取的坐标都是一样的,还有我们的上面动画为什么会偏差这个多,感觉这个高度貌似是我们的状态栏和标题栏的高度啊 ,为了验证我们的猜想,我们隐藏掉状态栏和标题栏试试
1
2
3
4
5
6
|
1
//获取当前窗体
2
final
Window window = getWindow();
3
//隐藏状态栏
4
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
5
//隐藏标题栏
6
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
效果如下:
效果实现了,没问题,说明真的是这个问题,那view.getLocationInWindow(int[] location)按照别人博客里面说的就是取的相对坐标啊,我们获取一下我们主界面的mRecyclerView的坐标看看
1
|
04
-
10
02
:
45
:
33.183
32056
-
32056
/com.qianmo.beziershopcart I/wangjtiao: ControllF:
0
,
210
|
可以看到我们的标题栏+状态栏高度是210,但是我们起始点的坐标是(1014,242)这个有问题啊,应该是(1014,32)这样我们的动画才会在正确的起始位置和结束位置啊。带着我们的疑问,查了半天资料,终于在一个论坛发现了
1
2
3
4
5
|
因为你的代码显示的界面 contentView < window = screen
为什么会相等呢,因为此时的Window就是包含状态栏+contentView的大小
不是你认为的 contentView = window < screen
除非你的view是从dialog 或者 popupWindow 上显示,
这时候getLocationInWindow获得的值就是相对的坐标。
|
所以getLocationInWindow方法获取的是状态栏+contentView的大小,而不是我们以为的contentView的大小,知道了这里我们基本上就知道怎么解决这个问题了,只需要减去这个高度就可以了,我们可以直接减去mRecyclerView的Y坐标即可,代码如下:
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
|
@Override
public
void
add(
final
View view,
int
position) {
//贝塞尔起始数据点
int
[] startPosition =
new
int
[
2
];
//贝塞尔结束数据点
int
[] endPosition =
new
int
[
2
];
//控制点
int
[] recyclerPosition =
new
int
[
2
];
view.getLocationInWindow(startPosition);
mImageViewShopCat.getLocationInWindow(endPosition);
mRecyclerView.getLocationInWindow(recyclerPosition);
PointF startF =
new
PointF();
PointF endF =
new
PointF();
PointF controllF =
new
PointF();
startF.x = startPosition[
0
];
startF.y = startPosition[
1
] - recyclerPosition[
1
];
endF.x = endPosition[
0
];
endF.y = endPosition[
1
] - recyclerPosition[
1
];
controllF.x = endF.x;
controllF.y = startF.y;
final
ImageView imageView =
new
ImageView(
this
);
main_layout.addView(imageView);
imageView.setImageResource(R.mipmap.ic_add_circle_blue_700_36dp);
imageView.getLayoutParams().width = getResources().getDimensionPixelSize(R.dimen.item_dish_circle_size);
imageView.getLayoutParams().height = getResources().getDimensionPixelSize(R.dimen.item_dish_circle_size);
imageView.setVisibility(View.VISIBLE);
imageView.setX(startF.x);
imageView.setY(startF.y);
ValueAnimator valueAnimator = ValueAnimator.ofObject(
new
BezierTypeEvaluator(controllF), startF, endF);
valueAnimator.addUpdateListener(
new
ValueAnimator.AnimatorUpdateListener() {
@Override
public
void
onAnimationUpdate(ValueAnimator animation) {
PointF pointF = (PointF) animation.getAnimatedValue();
imageView.setX(pointF.x);
imageView.setY(pointF.y);
Log.i(
"wangjtiao"
,
"viewF:"
+ view.getX() +
","
+ view.getY());
}
});
valueAnimator.setDuration(
800
);
valueAnimator.start();
}
|
看一下效果:
没问题了,这里的位置也没什么问题,再添加动画完成监听,移除刚刚new的ImageView
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
valueAnimator.addListener(
new
Animator.AnimatorListener() {
@Override
public
void
onAnimationStart(Animator animation) {
}
@Override
public
void
onAnimationEnd(Animator animation) {
imageView.setVisibility(View.GONE);
main_layout.removeView(imageView);
}
@Override
public
void
onAnimationCancel(Animator animation) {
}
@Override
public
void
onAnimationRepeat(Animator animation) {
}
});
|
- 购物车图标从缩小到放大的实现
这个就很简单了,就是一个简单的属性动画,然后将上面这几个动画放在集合中,代码如下:
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
|
@Override
public
void
add(
final
View view,
int
position) {
//贝塞尔起始数据点
int
[] startPosition =
new
int
[
2
];
//贝塞尔结束数据点
int
[] endPosition =
new
int
[
2
];
//控制点
int
[] recyclerPosition =
new
int
[
2
];
view.getLocationInWindow(startPosition);
mImageViewShopCat.getLocationInWindow(endPosition);
mRecyclerView.getLocationInWindow(recyclerPosition);
PointF startF =
new
PointF();
PointF endF =
new
PointF();
PointF controllF =
new
PointF();
startF.x = startPosition[
0
];
startF.y = startPosition[
1
] - recyclerPosition[
1
];
endF.x = endPosition[
0
];
endF.y = endPosition[
1
] - recyclerPosition[
1
];
controllF.x = endF.x;
controllF.y = startF.y;
final
ImageView imageView =
new
ImageView(
this
);
main_layout.addView(imageView);
imageView.setImageResource(R.mipmap.ic_add_circle_blue_700_36dp);
imageView.getLayoutParams().width = getResources().getDimensionPixelSize(R.dimen.item_dish_circle_size);
imageView.getLayoutParams().height = getResources().getDimensionPixelSize(R.dimen.item_dish_circle_size);
imageView.setVisibility(View.VISIBLE);
imageView.setX(startF.x);
imageView.setY(startF.y);
ValueAnimator valueAnimator = ValueAnimator.ofObject(
new
BezierTypeEvaluator(controllF), startF, endF);
valueAnimator.addUpdateListener(
new
ValueAnimator.AnimatorUpdateListener() {
@Override
public
void
onAnimationUpdate(ValueAnimator animation) {
PointF pointF = (PointF) animation.getAnimatedValue();
imageView.setX(pointF.x);
imageView.setY(pointF.y);
Log.i(
"wangjtiao"
,
"viewF:"
+ view.getX() +
","
+ view.getY());
}
});
ObjectAnimator objectAnimatorX =
new
ObjectAnimator().ofFloat(mImageViewShopCat,
"scaleX"
,
0
.6f,
1
.0f);
ObjectAnimator objectAnimatorY =
new
ObjectAnimator().ofFloat(mImageViewShopCat,
"scaleY"
,
0
.6f,
1
.0f);
objectAnimatorX.setInterpolator(
new
AccelerateInterpolator());
objectAnimatorY.setInterpolator(
new
AccelerateInterpolator());
AnimatorSet set =
new
AnimatorSet();
set.play(objectAnimatorX).with(objectAnimatorY).after(valueAnimator);
set.setDuration(
800
);
set.start();
}
|
最后的效果: