Android -- 贝塞尔二阶实现饿了么加入购物车效果

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:[email protected]
  */
 
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:[email protected]
  */
 
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:[email protected]
  */
 
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();
     }

  最后的效果:

  

猜你喜欢

转载自blog.csdn.net/tiankongcheng6/article/details/79445074
今日推荐