仿Periscope,映客用贝塞尔曲线实现点赞送爱心。

来源:互联网 发布:算法看哪本书 编辑:程序博客网 时间:2024/05/16 23:49
因为项目需要,开始研究动画。这是为了实现直播平台的点赞功能特效而做的,参阅了很多资料,大家想看 一些关于安卓的高机动画内容可以去关注一下他的[刘某人]http://http://my.csdn.net/qq_26787115的博客,相信会有一些收获的。
 首先我们来看一下效果:(因为自己还不太熟gif动态录制工具,就先拿的别人的效果图过来了)

首先我们要知道什么是贝塞尔曲线。告诉你们一个方法贝塞尔曲线
现在我们开始正题
首先我们想要去规划爱心的轨迹,我们需要通过贝塞尔曲线公式来进行一个计算!
 
 BezierEvaluator.java
  在这里面我们可以通过修改pointF1,pointF2等参数来修改我们的爱心运行时候的轨迹
package com.lgl.heartfaom;import android.animation.TypeEvaluator;import android.graphics.PointF;import android.util.Log;public class BezierEvaluator implements TypeEvaluator<PointF> {private PointF pointF1;private PointF pointF2;public BezierEvaluator(PointF pointF1, PointF pointF2) {this.pointF1 = pointF1;this.pointF2 = pointF2;}  //公式:B(t)=P(0)(1-t)^3+3P(1)t(1-t)*(1-t)@Override//求开始到结束时候的平滑过度的值//pointF1.y 运行曲线的高度public PointF evaluate(float time, PointF startValue, PointF endValue) {float timeLeft = 1.0f - time;PointF point = new PointF();// 结果//  float p0=startValue.x;//  float p1=pointF1.x;//  point.x=p0+(p1-p0)*timeLeft;  point.x = timeLeft * timeLeft * timeLeft * (startValue.x) + 3* timeLeft * timeLeft * time * (pointF1.x+450) + 3 * timeLeft* time * time * (pointF2.x) + time * time * time * (endValue.x);System.out.println("startValue.x"+startValue.x+"pointF1.x"+pointF1.x+"pointF2.x的值"+pointF2.x+"point.x的值"+point.x+"endValue.x"+endValue.x);      point.y = timeLeft * timeLeft * timeLeft * (startValue.y) + 3* timeLeft * timeLeft * time * (pointF1.y) + 3 * timeLeft* time * time * (pointF2.y) + time * time * time * (endValue.y);System.out.println("stratvalue.y的值" +startValue.y+"pointF1.y的值"+pointF1.y+"pointF2.y的值"+pointF2.y+"endValue.y的值"+endValue.y);return point;}}
<strong>下面这个PeriscopeLayout.java才是真正的大头</strong>
<div>package com.lgl.heartfaom;</div><div></div><div>import java.util.Random;</div><div></div><div>import android.animation.Animator;import android.animation.AnimatorListenerAdapter;import android.animation.AnimatorSet;import android.animation.ObjectAnimator;import android.animation.ValueAnimator;import android.content.Context;import android.graphics.PointF;import android.graphics.drawable.Drawable;import android.util.AttributeSet;import android.util.Log;import android.view.View;</div><div></div><div>import android.view.animation.Animation;import android.view.animation.AnimationUtils;import android.view.animation.LinearInterpolator;import android.widget.ImageView;import android.widget.RelativeLayout;</div><div></div><div>public class PeriscopeLayout extends RelativeLayout {</div><div></div><div>// private Interpolator line = new LinearInterpolator();// 线性// private Interpolator acc = new AccelerateInterpolator();// 加速// private Interpolator dce = new DecelerateInterpolator();// 减速// private Interpolator accdec = new AccelerateDecelerateInterpolator();// 先加速后减速// private Interpolator[] interpolators;  /**缩小动画**/    Animation mLitteAnimation = null;   Context content; private int mHeight;//整个布局的高度 private int mWidth;//整个布局的宽度 private LayoutParams lp; private Drawable[] drawables; private Random random = new Random(); private int dHeight;//爱心的高度 private int dWidth;//爱心的宽度   //content 上下文  //AttributeSet 属性集 //defStyleAttr 预设样式属性集 //defStyleRes 预设样式资源属性集 public PeriscopeLayout(Context context) {  super(context);   init(); } public PeriscopeLayout(Context context, AttributeSet attrs) {  super(context, attrs);  init(); } public PeriscopeLayout(Context context, AttributeSet attrs, int defStyleAttr) {  super(context, attrs, defStyleAttr);  init(); }  public PeriscopeLayout(Context context, AttributeSet attrs,   int defStyleAttr, int defStyleRes) {  super(context, attrs, defStyleAttr);  init(); }private void init() {  // 初始化显示的图片  drawables = new Drawable[3];  Drawable red = getResources().getDrawable(R.drawable.pl_red);  Drawable yellow = getResources().getDrawable(R.drawable.pl_yellow);  Drawable blue = getResources().getDrawable(R.drawable.pl_blue);  drawables[0] = red;  drawables[1] = yellow;  drawables[2] = blue;  // 获取图的宽高 用于后面的计算  // 注意 我这里3张图片的大小都是一样的,所以我只取了一个  dHeight = red.getIntrinsicHeight()/5*3;  dWidth = red.getIntrinsicWidth()/5*3;  // 底部 并且 水平居中  lp = new LayoutParams(dWidth, dHeight); //rightMargin设置爱心离父布局相对边缘的位置,可以通过这个属性来自由调节图片的位置  lp.rightMargin=80;  //center_Horizontal,allgn_parent_right  //lp.addRule(CENTER_IN_PARENT,TRUE);// 这里的TRUE 要注意 不是true     lp.addRule(ALIGN_PARENT_RIGHT, TRUE);       lp.addRule(ALIGN_PARENT_BOTTOM, TRUE);  // 初始化插补器//  interpolators = new Interpolator[4];//  interpolators[0] = line;//  interpolators[3] = acc;//  interpolators[1] = dce;//  interpolators[2] = accdec; }</div><div></div><div> @Override //获取view的宽,高。 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  mWidth = getMeasuredWidth();  mHeight = getMeasuredHeight();  super.onMeasure(widthMeasureSpec, heightMeasureSpec);//  mWidth = getMeasuredWidth();//  mHeight = getMeasuredHeight(); }  //添加心跳图片,在此处添加等级对应的图片资源 public  void addHeart() { //缩小动画  mLitteAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.scalelitte);  //动画  // 随机选一个    ImageView imageView = new ImageView(getContext());    imageView.startAnimation(mLitteAnimation);            imageView.setImageDrawable(drawables[random.nextInt(1)]);            imageView.setLayoutParams(lp);              //缩小  addView(imageView);  Animator set = getAnimator(imageView);  set.addListener(new AnimEndListener(imageView));  set.start(); }  //获得动画器 private Animator getAnimator(View target) {  AnimatorSet set = getEnterAnimtor(target);  ValueAnimator bezierValueAnimator = getBezierValueAnimator(target);  AnimatorSet finalSet = new AnimatorSet();  finalSet.playSequentially(set);  finalSet.playSequentially(set, bezierValueAnimator);  //finalSet.setInterpolator(interpolators[random.nextInt(4)]);  /*Random.nextint() 和Math.random()的区别                    前者生成的随机数效率高于后者,时间上前者大约是后者50%到80%的时间.                     造成这个原因如下:          Math.random()是Random.nextDouble()的一个内部方法.          Random.nextDouble()使用Random.next()两次,均匀的分布范围为0到1 - (2 ^ -53).          Random.nextInt(n)的使用Random.next()不多于两次, 返回值范围为0到n - 1的分布         ****         *nextInt(4)将产生0,1,2,3这4个数字中的任何一个数字,注意这里不是0-4,而是0-3。                         但下限总是零,不能更改   *    * */     finalSet.setTarget(target);  return finalSet; }  //字面上的意思 获取进入的动画器 private AnimatorSet getEnterAnimtor(final View target) {  //关于这边的内容 可以去 参考 郭大神的博客  //http://blog.csdn.net/guolin_blog/article/details/43816093       //大概意思是获取一个float类型数值的动画(target:是对象,假如我们是textview的动画,我们就传入其对象名字)  //View.ALPHA 是我们用到的动画  //0.2f,lf 跟我们动画的透明值。  ObjectAnimator alpha = ObjectAnimator.ofFloat(target, View.ALPHA, 0.2f,    1f);  ObjectAnimator scaleX = ObjectAnimator.ofFloat(target, View.SCALE_X,    0.2f, 1f);  ObjectAnimator scaleY = ObjectAnimator.ofFloat(target, View.SCALE_Y,    0.2f, 1f);  AnimatorSet enter = new AnimatorSet();  //这里要设置成0,不然的话在右上角也会出现一个爱心  enter.setDuration(0);  enter.setInterpolator(new LinearInterpolator());  enter.playTogether(alpha, scaleX, scaleY);  enter.setTarget(target);  return enter; } /*  *   *   * */ private ValueAnimator getBezierValueAnimator(View target) {</div><div></div><div>  // 初始化一个贝塞尔计算器- - 传入  BezierEvaluator evaluator = new BezierEvaluator(getPointF(2),    getPointF(1));</div><div></div><div>  // 这里最好画个图 理解一下 传入了起点 和 终点  //mHeight - dHeight-200  //mWidth - dWidth) / 7*6 代表的心跳的起点位置在靠右边占整个屏幕的七分之六  ValueAnimator animator = ValueAnimator.ofObject(evaluator, new PointF(    (mWidth - dWidth) / 7*6, mHeight - dHeight-200),    new PointF((mWidth - dWidth) / 7*6, getMeasuredHeight()/2));  animator.addUpdateListener(new BezierListenr(target));  animator.setTarget(target);  //设置心跳动画的持续时间  animator.setDuration(4000);  return animator; }</div><div></div><div> /**  * 获取中间的两个 点  *  * @param scale  */ private PointF getPointF(int scale) {</div><div></div><div>  PointF pointF = new PointF();  int Startpx=(mWidth - dWidth) / 7*6;  //pointF.x = random.nextInt(getMeasuredWidth()-(mWidth - dWidth) / 7*6);//这里是 是为了控制 x轴活动范围,看效果 随意~~  //pointF.x=random.nextInt(getMeasuredWidth());  pointF.x = random.nextInt(Startpx+getMeasuredWidth()/100+25);   Log.i("x", "随机值");  pointF.y =  getMeasuredHeight()/2;  // 再Y轴上 为了确保第二个点 在第一个点之上,我把Y分成了上下两半 这样动画效果好一些 也可以用其他方法  //pointF.y = random.nextInt((mHeight - 100))/scale;    // pointF.x = random.nextInt((mWidth - 100));  //        //pointF.y = random.nextInt((mHeight - 100))/scale;  return pointF; }</div><div></div><div> private class BezierListenr implements ValueAnimator.AnimatorUpdateListener {</div><div></div><div>  private View target;</div><div></div><div>  public BezierListenr(View target) {   this.target = target;  }</div><div></div><div>  @Override  public void onAnimationUpdate(ValueAnimator animation) {   // 这里获取到贝塞尔曲线计算出来的的x y值 赋值给view 这样就能让爱心随着曲线走啦   PointF pointF = (PointF) animation.getAnimatedValue();   target.setX(pointF.x);   target.setY(pointF.y);   // 这里顺便做一个alpha动画   target.setAlpha((float) (1-animation.getAnimatedFraction()));  // target.setAlpha(1 - animation.getAnimatedFraction());  } }</div><div></div><div> private class AnimEndListener extends AnimatorListenerAdapter {  private View target;</div><div></div><div>  public AnimEndListener(View target) {   this.target = target;  }</div><div></div><div>  @Override  public void onAnimationEnd(Animator animation) {   super.onAnimationEnd(animation);   // 因为不停的add 导致子view数量只增不减,所以在view动画结束后remove掉   removeView((target));  } }}</div>


大家耐心的看下注释,跟着这个照着葫芦画瓢 也能做出这样一个动画的

为了实现点击屏幕出现这个爱心 所有 我们 要另外在一个类里面实现他的屏幕点击事情。

微笑 

public boolean onTouchEvent(MotionEvent event) {
  // TODO Auto-generated method stub
  int touchEvent = event.getAction(); 
   switch (touchEvent)
   {
   //监听屏幕被按下
   case MotionEvent.ACTION_DOWN:
   //调用添加泡泡的方法
    periscopeLayout.addHeart();

    break;
   }
  return super.onTouchEvent(event);
 }


我们需要实现一个图片缩小到大的动画,就需要在res文件下新建一个anim 文件夹 写我们的xml动画
<?xml version="1.0" encoding="utf-8"?>
<scale
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:fromXScale="0.0"
   android:toXScale="1.0"
   android:fromYScale="0.0"
   android:toYScale="1.0"
   android:pivotX="50%"
   android:pivotY="50%"
   android:duration="2000">
</scale>


我们实现点赞的代码也就是这么简单了,demo下载地址:demo下载链接(配合博客一起看)

对这个编辑器还是不太懂,写出来的东西可读性没有人家那些好。不过后面多写了,也就会慢慢熟悉了。
http://download.csdn.net/detail/ningzhouxu/9528218







 





0 0
原创粉丝点击