//自定义view public class HeartStar extends ViewGroup { private List<Drawable> mStarDrawable; private int mWidth; //整个控件的宽度 private int mHeight; //整个控件的高度 // private Random random = new Random(); public HeartStar(Context context) { this(context, null); } public HeartStar(Context context, AttributeSet attrs) { this(context, attrs, 0); } public HeartStar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private void init(final Context context) { mStarDrawable = new ArrayList<>(); //初始化图片资源 mStarDrawable.add(getResources().getDrawable(R.drawable.find_like_img)); ImageView image_heard = new ImageView(context); image_heard.setImageDrawable(mStarDrawable.get(0)); image_heard.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); addView(image_heard); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { measureChildren(widthMeasureSpec, heightMeasureSpec); //获取view的宽高测量模式 int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); //保存测量高度 setMeasuredDimension(widthSize, heightSize); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { Log.i("wangjitao", "l:" + l + ",t:" + t + ",r:" + r + ",b:" + b); View child = getChildAt(0); int childW = child.getMeasuredWidth(); int childH = child.getMeasuredHeight(); child.layout((mWidth - childW) / 2, (mHeight - childH), (mWidth - childW) / 2 + childW, mHeight); } //属性动画和插补器了解 //申明属性 private PointF mStartPoint, mEndPoint; @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { mStartPoint=new PointF(); mEndPoint=new PointF(); super.onSizeChanged(w, h, oldw, oldh); mWidth = getMeasuredWidth(); mHeight = getMeasuredHeight(); // 初始化各个点 //借用子view控件中的宽高 View child = getChildAt(0); int childW = child.getMeasuredWidth(); int childH = child.getMeasuredHeight(); mStartPoint.x = (mWidth - childW) / 2; mStartPoint.y = mHeight - childH; mEndPoint.x = (mWidth - childW) / 2; mEndPoint.y = 0 - childH; } //自定义TypeEvaluator public class BezierTypeEvaluator implements TypeEvaluator<PointF> { @Override public PointF evaluate(float fraction, PointF startValue, PointF endValue) { PointF pointCur = new PointF(); pointCur.x = mStartPoint.x + fraction * (endValue.x - mStartPoint.x); pointCur.y = mStartPoint.y + fraction * (endValue.y - mStartPoint.y); return pointCur; } } //向外部提供方法,用于点击事件触发动画发生 /** * 开始动画 */ public void startRunning() { BezierTypeEvaluator bezierTypeEvaluator = new BezierTypeEvaluator(); ValueAnimator valueAnimator = ValueAnimator.ofObject(bezierTypeEvaluator, mStartPoint, mEndPoint); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { PointF pointF = (PointF) animation.getAnimatedValue(); getChildAt(0).setX(pointF.x); getChildAt(0).setY(pointF.y); } }); valueAnimator.setDuration(3000); valueAnimator.start(); }
}
activity.xml中:
<com.example.administrator.heart.HeartStar android:id="@+id/likestar" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:id="@+id/btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="翻滚吧,贝塞尔" />
activity点击事件
@Override public void onClick(View v) { switch (v.getId()) { case R.id.btn: // likestar = (HeartStar) findViewById(R.id.likestar); likestar.startRunning(); break; } }
效果图如下:
添加贝塞尔曲线
但是我们最终的效果图是每个圆心都是做无规则的曲线上升,这里我们就要使用贝塞尔三阶曲线公式了,这里不了解的童鞋可以去这一篇弄懂,不然后面的计算你是看不懂怎么来的。
//在刚才的 evaluate()方法中
private PointF mControllPoint1, mControllPoint2;
private Random random = new Random(); //随机
//自定义TypeEvaluator public class BezierTypeEvaluator implements TypeEvaluator<PointF> { public BezierTypeEvaluator(PointF mControllPointOne, PointF mControllPointTwo) { mControllPointOne=new PointF(); mControllPointTwo=new PointF(); //设置值 mControllPointOne.x = random.nextInt(mWidth / 2); mControllPointOne.y = random.nextInt(mHeight / 2) + mHeight / 2; mControllPointTwo.x = random.nextInt(mWidth / 2) + mWidth / 2; mControllPointTwo.y = random.nextInt(mHeight / 2); mControllPoint1 = mControllPointOne; mControllPoint2 = mControllPointTwo; } @Override public PointF evaluate(float fraction, PointF startValue, PointF endValue) { PointF pointCur = new PointF(); pointCur.x = mStartPoint.x * (1 - fraction) * (1 - fraction) * (1 - fraction) + 3 * mControllPoint1.x * fraction * (1 - fraction) * (1 - fraction) + 3 * mControllPoint2.x * (1 - fraction) * fraction * fraction + endValue.x * fraction * fraction * fraction;// 实时计算最新的点X坐标 pointCur.y = mStartPoint.y * (1 - fraction) * (1 - fraction) * (1 - fraction) + 3 * mControllPoint1.y * fraction * (1 - fraction) * (1 - fraction) + 3 * mControllPoint2.y * (1 - fraction) * fraction * fraction + endValue.y * fraction * fraction * fraction;// 实时计算最新的点Y坐标 return pointCur; } } //向外部提供方法,用于点击事件触发动画发生 /** * 开始动画 */ public void startRunning() { BezierTypeEvaluator bezierTypeEvaluator = new BezierTypeEvaluator(mControllPoint1, mControllPoint2); ValueAnimator valueAnimator = ValueAnimator.ofObject(bezierTypeEvaluator, mStartPoint, mEndPoint); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { PointF pointF = (PointF) animation.getAnimatedValue(); getChildAt(0).setX(pointF.x); getChildAt(0).setY(pointF.y); } }); valueAnimator.setDuration(3000); valueAnimator.start(); }
再看看运行效果