//自定义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();
}
再看看运行效果