android 通过贝塞尔曲线 实现爱心点赞功能
16lz
2022-05-22
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; }}
估值器:BezierEvaluator
package mk.denganzhi.com.zhiwenku;import android.animation.TypeEvaluator;import android.graphics.PointF;public class BezierEvaluator implements TypeEvaluator {private PointF pointF1;private PointF pointF2;public BezierEvaluator(PointF pointF1, PointF pointF2) {// TODO Auto-generated constructor stubthis.pointF1 = pointF1;this.pointF2 = pointF2;}@Overridepublic PointF evaluate(float t, PointF point0, PointF point3) {// b(t)=p0*(1-t)*(1-t)*(1-t)+3*p1*t*(1-t)*(1-t)+3*p2*t*t*(1-t)+p3*t*t*tPointF point = new PointF();point.x = point0.x*(1-t)*(1-t)*(1-t)+3*pointF1.x*t*(1-t)*(1-t)+3*pointF2.x*t*t*(1-t)+point3.x*t*t*t;point.y = point0.y*(1-t)*(1-t)*(1-t)+3*pointF1.y*t*(1-t)*(1-t)+3*pointF2.y*t*t*(1-t)+point3.y*t*t*t;return point;}}
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布局
效果图功能:
源码地址:https://download.csdn.net/download/dreams_deng/12255079
归纳:使用贝塞尔公式绘制曲线路径
package mk.denganzhi.com.zhiwenku;import android.animation.ValueAnimator;import android.content.Context;import android.graphics.PointF;import android.graphics.drawable.BitmapDrawable;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.view.WindowManager;import android.widget.ImageButton;import android.widget.ImageView;public class TestActivity extends AppCompatActivity { ImageButton mybtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); mybtn = (ImageButton) findViewById(R.id.mybtn); } boolean isFlag=false; public void startAnimation(View view) { WindowManager wm = (WindowManager) this .getSystemService(Context.WINDOW_SERVICE); final int width = wm.getDefaultDisplay().getWidth(); int height = wm.getDefaultDisplay().getHeight(); float startX= mybtn.getLeft(); float startY =mybtn.getTop(); PointF pointF0 = new PointF(startX, startY); PointF pointF2 = new PointF(startX-50,startY-10); PointF pointF3 = new PointF(startX-300,startY-500); // 贝塞尔公式 PointF pointF4 = new PointF(width/2-mybtn.getWidth()/2,height/2-mybtn.getHeight()/2); BezierEvaluator evaluator = new BezierEvaluator(pointF2,pointF3); Log.e("denganzhi","startx:"+startX+" startY:"+startY); ValueAnimator animator = ValueAnimator.ofObject(evaluator, pointF0,pointF4); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { PointF pointF = (PointF) animation.getAnimatedValue();// iv.setX(pointF.x);// iv.setY(pointF.y); int scaleBeiShu= (width)/mybtn.getWidth(); mybtn.setX(pointF.x); mybtn.setY(pointF.y); Log.e("denganzhi1","坐标是:x"+ pointF.x +" y:" + pointF.y +" scaleBeiShu:"+scaleBeiShu); if(pointF.x<350){ if(!isFlag){ mybtn.setImageDrawable(new BitmapDrawable());/** * .scaleY(2) : 放大到2倍 * scaleYBy(1): 在原来基础上放大1倍,累加过程 * * scrollTo * scrollBy */ mybtn.animate() .scaleYBy(1) .scaleXBy(scaleBeiShu) .setDuration(3000); isFlag=true; } } // mybtn.setAlpha(1-animation.getAnimatedFraction());//1~0 百分比 } }); animator.setDuration(1000); animator.start(); }}
activity_test 布局:
<?xml version="1.0" encoding="utf-8"?>
效果:
直接起点,终点, 中间2个点就可以使用贝塞尔曲线,绘制绘制轨迹
问题就是:不知道它的点,知道点以后才知道轨迹
更多相关文章
- android animation
- Android让帧动画在结束时消失
- Android分享界面制作(底部滑出动画)
- Android(安卓)ActionBar中的按钮添加旋转动画
- 一个不错的启动菜单显示屏动画效果
- android特效展示一:ListView
- android 动画之Scroller
- Android中Activity跳转和切换动画
- Android(安卓)中 PopupWindow的用法 汇总