android 通过贝塞尔曲线 实现爱心点赞功能

Jcinta ·
更新时间:2024-11-10
· 868 次阅读

android 通过贝塞尔曲线 实现爱心点赞功能:
  ValueAnimatior:
核心功能:
    已知起点p0, 终p3,中间点 p1、p2  通过贝塞尔曲线 计算路径中各个点
案例1:  重力抛物线  
案例2:  爱心点赞功能

核心代码:LoveLayout 

package mk.denganzhi.com.zhiwenku; import java.util.Random; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.content.Context; import android.graphics.PointF; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.Log; import android.widget.ImageView; import android.widget.RelativeLayout; import mk.denganzhi.com.zhiwenku.BezierEvaluator; import mk.denganzhi.com.zhiwenku.R; public class LoveLayout extends RelativeLayout { Drawable[] drawables = new Drawable[3]; private Random random = new Random(); private int dHeight; private int dWidth; private LayoutParams params; private int mWidth; private int mHeight; public LoveLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } public LoveLayout(Context context) { super(context); init(); } public LoveLayout(Context context, AttributeSet attrs) { super(context, attrs); init(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 必须在测量完毕以后才知道控件高度、和宽度 mWidth = getMeasuredWidth(); mHeight = getMeasuredHeight(); } private void init() { //准备图片集合 drawables[0] = getResources().getDrawable(R.drawable.red); drawables[1] = getResources().getDrawable(R.drawable.yellow); drawables[2] = getResources().getDrawable(R.drawable.blue); //得到图片的原始高度 dWidth = drawables[0].getIntrinsicWidth(); dHeight = drawables[0].getIntrinsicHeight(); params = new LayoutParams(dWidth, dHeight); //将iv添加到父容器底部、水平居中位置 params.addRule(CENTER_HORIZONTAL); params.addRule(ALIGN_PARENT_BOTTOM); } // 1. 第一步: 绘制ImageView 心形 public void addLoveIcon(){ //添加心形,并开始执行动画 final ImageView iv = new ImageView(getContext()); iv.setImageDrawable(drawables[random.nextInt(3)]); //将iv添加到父容器底部、水平居中位置 iv.setLayoutParams(params); addView(iv); //开始属性动画:平移、透明度渐变、缩放动画 AnimatorSet set = getAnimator(iv); //监听动画执行完毕,将iv移除或者复用 set.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); removeView(iv); } }); set.start(); } // 得到一个iv的动画集合 private AnimatorSet getAnimator(ImageView iv) { //平移、透明度渐变、缩放动画 //1.alpha动画 ObjectAnimator alpha = ObjectAnimator.ofFloat(iv, "alpha", 0.3f,1f); //2.缩放动画 ObjectAnimator scaleX = ObjectAnimator.ofFloat(iv, "scaleX", 0.3f,1f); ObjectAnimator scaleY = ObjectAnimator.ofFloat(iv, "scaleY", 0.3f,1f); //三个动画同时执行 AnimatorSet enter = new AnimatorSet(); enter.setDuration(600); enter.playTogether(alpha,scaleX,scaleY); // enter.setTarget(iv); //设置平移的曲线动画---贝塞尔曲线 // 2. 第二步启动估值器 ValueAnimator bezierAnimator = getBezierValueAnimator(iv); AnimatorSet set = new AnimatorSet(); //同时依次执行 实现属性动画 set.playSequentially(enter,bezierAnimator); set.setTarget(iv); return set; } //得到一个贝塞尔曲线动画 private ValueAnimator getBezierValueAnimator(final ImageView iv) { //根据贝塞尔公式确定四个点(起始点p0,拐点1p1,拐点2p2,终点p3) PointF pointF0 = new PointF((mWidth-dWidth)/2, mHeight-dHeight); PointF pointF3 = new PointF(random.nextInt(mWidth), 0); PointF pointF1 = getPointF(1); PointF pointF2 = getPointF(2); BezierEvaluator evaluator = new BezierEvaluator(pointF1,pointF2); ValueAnimator animator = ValueAnimator.ofObject(evaluator, pointF0,pointF3); animator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { PointF pointF = (PointF) animation.getAnimatedValue(); // iv.setX(pointF.x); // iv.setY(pointF.y); iv.setX(pointF.x); iv.setY(pointF.y); Log.e("denganzhi1","坐标是:x"+ pointF.x +" y:" + pointF.y); iv.setAlpha(1-animation.getAnimatedFraction());//1~0 百分比 } }); animator.setDuration(10000); return animator; } private PointF getPointF(int i) { PointF pointF = new PointF(); pointF.x = random.nextInt(mWidth); if(i==1){ pointF.y = random.nextInt(mHeight/2)+mHeight/2; }else{ pointF.y = random.nextInt(mHeight/2); } return pointF; } }

 MainActivity代码,使用控件:

package mk.denganzhi.com.zhiwenku; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; public class MainActivity extends AppCompatActivity { private LoveLayout loveLayout; MyBazierLayout myBazierLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); loveLayout = (LoveLayout)findViewById(R.id.loveLayout); myBazierLayout = findViewById(R.id.loveLayout2); } public void start(View view){ loveLayout.addLoveIcon(); // myBazierLayout.addLoveIcon(); } public void translate(View view) { // myBazierLayout.translateFun(); } }

 MainActivity 的xml布局

需要 登录 后方可回复, 如果你还没有账号请 注册新账号