一、概述,最后面有完整代码下载地址

老规矩先上图


好了,基本就是这个样子,录完的视频用格式工厂转换完就这个样子了,将就看吧

二、定义我们自己的Layout

[java]  view plain  copy
  1. /** 
  2.  * @author 刘洋巴金 
  3.  * @date 2017-4-27 
  4.  *  
  5.  * 定义我们自己的布局 
  6.  * */  
  7. public class LoveLayout extends RelativeLayout{  
  8.   
  9.     private Context context;  
  10.     private LayoutParams params;  
  11.     private Drawable[] icons = new Drawable[4];  
  12.     private Interpolator[] interpolators = new Interpolator[4];  
  13.     private int mWidth;  
  14.     private int mHeight;  
  15.       
  16.     public LoveLayout(Context context, AttributeSet attrs) {  
  17.         super(context, attrs);  
  18.           
  19.         this.context = context;  
  20.         initView();  
  21.     }  
  22.   
  23.     private void initView() {  
  24.           
  25.         // 图片资源  
  26.         icons[0] = getResources().getDrawable(R.drawable.green);  
  27.         icons[1] = getResources().getDrawable(R.drawable.purple);  
  28.         icons[2] = getResources().getDrawable(R.drawable.red);  
  29.         icons[3] = getResources().getDrawable(R.drawable.yellow);  
  30.           
  31.         // 插值器  
  32.         interpolators[0] = new AccelerateDecelerateInterpolator(); // 在动画开始与结束的地方速率改变比较慢,在中间的时候加速  
  33.         interpolators[1] = new AccelerateInterpolator();  // 在动画开始的地方速率改变比较慢,然后开始加速  
  34.         interpolators[2] = new DecelerateInterpolator(); // 在动画开始的地方快然后慢  
  35.         interpolators[3] = new LinearInterpolator();  // 以常量速率改变  
  36.           
  37.         int width = icons[0].getIntrinsicWidth();  
  38.         int height = icons[0].getIntrinsicWidth();  
  39.         params = new LayoutParams(width, height);  
  40.         params.addRule(CENTER_HORIZONTAL, TRUE);  
  41.         params.addRule(ALIGN_PARENT_BOTTOM, TRUE);  
  42.     }  
基本就是做了初始化,声明了4个drawable,也就是4个颜色的心,4个插值器,用于控制动画速率的改变,设置初始位置为屏幕的下边中点处。

[java]  view plain  copy
  1. @Override  
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  3.     // TODO Auto-generated method stub  
  4.     super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  5.     mWidth = getMeasuredWidth();  
  6.     mHeight = getMeasuredHeight();  
  7. }  
  8.       
  9. public void addLoveView() {  
  10.     // TODO Auto-generated method stub  
  11.     final ImageView iv = new ImageView(context);  
  12.     iv.setLayoutParams(params);  
  13.     iv.setImageDrawable(icons[new Random().nextInt(4)]);  
  14.     addView(iv);  
  15.           
  16.     // 开启动画,并且用完销毁  
  17.     AnimatorSet set = getAnimatorSet(iv);  
  18.     set.start();  
  19.     set.addListener(new AnimatorListenerAdapter() {  
  20.         @Override  
  21.         public void onAnimationEnd(Animator animation) {  
  22.             // TODO Auto-generated method stub  
  23.             super.onAnimationEnd(animation);  
  24.             removeView(iv);  
  25.         }  
  26.     });  
  27. }  
用于添加心型效果。动画结束后,再移除

[java]  view plain  copy
  1. /** 
  2.  * 获取动画集合 
  3.  * @param iv  
  4.  * */  
  5. private AnimatorSet getAnimatorSet(ImageView iv) {  
  6.           
  7.     // 1.alpha动画  
  8.     ObjectAnimator alpha = ObjectAnimator.ofFloat(iv, "alpha"0.3f, 1f);  
  9.           
  10.     // 2.缩放动画  
  11.     ObjectAnimator scaleX = ObjectAnimator.ofFloat(iv, "scaleX"0.2f, 1f);  
  12.     ObjectAnimator scaleY = ObjectAnimator.ofFloat(iv, "scaleY"0.2f, 1f);  
  13.           
  14.     // 动画集合  
  15.     AnimatorSet set = new AnimatorSet();  
  16.     set.playTogether(alpha, scaleX, scaleY);  
  17.     set.setDuration(500);  
  18.           
  19.     // 贝塞尔曲线动画  
  20.     ValueAnimator bzier = getBzierAnimator(iv);  
  21.           
  22.     AnimatorSet set2 = new AnimatorSet();  
  23.     set2.playSequentially(set, bzier);  
  24.     set2.setTarget(iv);  
  25.     return set2;  
  26. }  
playTogether:几个动画同时执行

ObjectAnimator为属性动画,不熟悉可以百度了解下

然后是设置贝塞尔曲线动画

playSequentially:动画依次执行

[java]  view plain  copy
  1. /** 
  2.  * 贝塞尔动画 
  3.  * */  
  4. private ValueAnimator getBzierAnimator(final ImageView iv) {  
  5.         // TODO Auto-generated method stub  
  6.     PointF[] PointFs = getPointFs(iv); // 4个点的坐标  
  7.     BasEvaluator evaluator = new BasEvaluator(PointFs[1], PointFs[2]);  
  8.     ValueAnimator valueAnim = ValueAnimator.ofObject(evaluator, PointFs[0], PointFs[3]);  
  9.     valueAnim.addUpdateListener(new AnimatorUpdateListener() {  
  10.               
  11.         @Override  
  12.         public void onAnimationUpdate(ValueAnimator animation) {  
  13.             // TODO Auto-generated method stub  
  14.             PointF p = (PointF) animation.getAnimatedValue();  
  15.             iv.setX(p.x);  
  16.             iv.setY(p.y);  
  17.             iv.setAlpha(1- animation.getAnimatedFraction()); // 透明度  
  18.         }  
  19.     });  
  20.     valueAnim.setTarget(iv);  
  21.     valueAnim.setDuration(3000);  
  22.     valueAnim.setInterpolator(interpolators[new Random().nextInt(4)]);  
  23.     return valueAnim;  
  24. }  
  25.   
  26. private PointF[] getPointFs(ImageView iv) {  
  27.     // TODO Auto-generated method stub  
  28.     PointF[] PointFs = new PointF[4];  
  29.     PointFs[0] = new PointF(); // p0  
  30.     PointFs[0].x = (mWidth- params.width)/ 2;  
  31.     PointFs[0].y = mHeight - params.height;  
  32.       
  33.     PointFs[1] = new PointF(); // p1  
  34.     PointFs[1].x = new Random().nextInt(mWidth);    
  35.     PointFs[1].y = new Random().nextInt(mHeight /2) + mHeight / 2 + params.height;  
  36.       
  37.     PointFs[2] = new PointF(); // p2  
  38.     PointFs[2].x = new Random().nextInt(mWidth);    
  39.     PointFs[2].y = new Random().nextInt(mHeight /2);  
  40.           
  41.     PointFs[3] = new PointF(); // p3  
  42.     PointFs[3].x = new Random().nextInt(mWidth);    
  43.     PointFs[3].y = 0;  
  44.     return PointFs;  
  45. }  
先获得4个点的坐标


p0坐标:x坐标((布局的宽-心形图片宽)除以2),y坐标(布局的高 -心形图片高),这样获得的是顶部部水平中心点的坐标。

p1坐标:x坐标(横坐标中的随机位置),y坐标(布局一半的高度 加上 0到一半高度范围内的随机坐标+心形的高度的一半)。这样取到的横坐标是在布局宽度之内的随机坐标,纵坐标为整个路径高度中部以上的随机坐标。

p2坐标:与p1类似,横坐标是在布局宽度之内的随机坐标,纵坐标为整个路径高度中部以下的随机坐标。

p3坐标:控件底部中心点

好了知道4个坐标了,那么开始计算路径

首先为了计算贝塞尔曲线,我们先写一个估值器

[java]  view plain  copy
  1. /** 
  2.  * @author 刘洋巴金 
  3.  * @date 2017-4-27 
  4.  *  
  5.  * 估值器,计算路径 
  6.  * */  
  7. public class BasEvaluator implements TypeEvaluator {  
  8.   
  9.     private PointF p1;  
  10.     private PointF p2;  
  11.   
  12.     public BasEvaluator(PointF p1, PointF p2) {  
  13.         super();  
  14.         this.p1 = p1;  
  15.         this.p2 = p2;  
  16.     }  
  17.   
  18.     @Override  
  19.     public PointF evaluate(float fraction, PointF p0, PointF p3) {  
  20.         // TODO Auto-generated method stub  
  21.         PointF pointf = new PointF();  
  22.           
  23.         // 贝塞尔曲线公式  p0*(1-t)^3 + 3p1*t*(1-t)^2 + 3p2*t^2*(1-t) + p3^3  
  24.         pointf.x = p0.x * (1-fraction) *(1-fraction ) * (1-fraction)  
  25.                    +3*p1.x * fraction *(1-fraction )*(1-fraction )  
  26.                    +3*p2.x *fraction  *fraction  *(1-fraction )  
  27.                    +p3.x*fraction *fraction *fraction ;   
  28.         pointf.y = p0.y * (1-fraction ) *(1-fraction ) * (1-fraction )  
  29.                 +3*p1.y * fraction *(1-fraction )*(1-fraction )  
  30.                 +3*p2.y *fraction  *fraction  *(1-fraction )  
  31.                 +p3.y*fraction *fraction *fraction ;   
  32.         return pointf;  
  33.     }  
  34. }  
TypeEvaluator:估值器回调evaluate方法,用于动态的改变动画的属性值。

evaluate三个参数:

1.fraction,默认传入的就是(currentTime - startTime) / duration,动画执行的时间除以总的时间比值,可以理解为变化率。当duration到了的时候,正好,起始点变到终点。

2.起始点

3.终点

根据三个参数,计算点的根据每毫秒的变化率,计算点的路径轨迹。

好了贝塞尔曲线动画就讲完了,然后再把动画绑定到控件上。

最后在MainActivity中根据点击事件,进行增加心型就好了。

[java]  view plain  copy
  1. btn_press = (Button)findViewById(R.id.btn_press);  
  2. ll_love = (LoveLayout)findViewById(R.id.ll_love);  
  3. btn_press.setOnClickListener(new OnClickListener() {  
  4.               
  5.     @Override  
  6.     public void onClick(View v) {  
  7.         // TODO Auto-generated method stub  
  8.         ll_love.addLoveView();  
  9.     }  
  10. });  

完整Demo代码下载地址:Android仿某直播点赞飘爱心

更多相关文章

  1. Android仿淘宝头条滚动广告条
  2. Fragment的使用
  3. Android(安卓)动画之AlphaAnimation应用详解
  4. Android基础笔记(十)- 帧动画、补间动画具体解释、对话框
  5. 基于AndroidStudio开发的简单登陆页面制作
  6. Android学习笔记(三)UI
  7. Android(安卓)RelativeLayout布局
  8. Android动画-Interpolator(插值器)大全
  9. AndroidStudio插件:布局文件转化Databinding

随机推荐

  1. Android Diaolog与AlertDialog用法实例
  2. Android(安卓)Handler之从主线程往子线程
  3. android消息处理——Thread、Looper、Han
  4. android使用ViewPager实现欢迎引导页
  5. android开发-NDK-JNI入门教程
  6. Android开发规范最新详尽版下载
  7. 关于 Android 下的自动化测试
  8. Android 资源文件使用方法详解
  9. android跳转到系统的各项设置界面
  10. 熟练使用 Android Studio