效果:
- 三阶贝塞尔曲线执行原理过程
P0点是起始点 , P3 点是终止点 , P 1 和 P 2 点是控制点 ;
- 三阶贝塞尔曲控制点计算公式
根据比例 , 绘制出 P0与 P2之间的二阶贝塞尔曲线 , 以 P1 为控制点 , 绘制出直线 AB ;然后 绘制 P1与 P3之间的二阶贝塞尔曲线 , 以 P2为控制点 , 绘制出直线 BC;最后 计算A到C之间的二阶贝塞尔曲线 , 以 B 点作为 控制点
一、实现图片由下往上随机曲线飘动。
public class FloatAnimView extends FrameLayout {
public FloatAnimView(@NonNull Context context) {
this(context, null);
}
public FloatAnimView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public FloatAnimView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* 添加view
*/
public void addItemView() {
ImageView imageView = new ImageView(getContext());
imageView.setImageResource(R.mipmap.icon_sx);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(10, 10);
layoutParams.gravity = Gravity.BOTTOM;
addView(imageView, layoutParams);
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) imageView.getLayoutParams();
marginLayoutParams.leftMargin = getMeasuredWidth() / 2;
animIcon(imageView);
}
private int[] size = {20, 15, 16, 18, 19, 13, 12, 11, 8, 5, 6};
/**
* 开始动画
*
* @param animIcon
*/
public void animIcon(ImageView animIcon) {
// animIcon.setRotation(new Random().nextInt(360));
/*随机显示图片的大小*/
ValueAnimator animator = ValueAnimator.ofFloat(10, size[new Random().nextInt(10)]);
animator.setDuration(500);
animator.start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(@NonNull ValueAnimator animation) {
float f = (float) animation.getAnimatedValue();
animIcon.setScaleX(f);
animIcon.setScaleY(f);
}
});
PointF[] p = initPointF();
Bezier bezier = new Bezier(p[1],p[2],p[3]);
ValueAnimator valueAnimator = ValueAnimator.ofObject(bezier, p[0], p[3]);
valueAnimator.setDuration(1500);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(@NonNull ValueAnimator animation) {
PointF pointF = (PointF) animation.getAnimatedValue();
animIcon.setX(pointF.x);
animIcon.setY(pointF.y);
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
FloatAnimView.this.removeView(animIcon);
valueAnimator.reverse();
}
});
valueAnimator.start();
}
private PointF p0, p1, p2, p3;
public PointF[] initPointF() {
PointF[] pointFS = new PointF[4];
p0 = new PointF(getMeasuredWidth() / 2, getMeasuredHeight());
PointF p1 = new PointF(new Random().nextInt(getMeasuredWidth()), getMeasuredHeight() / 2);
PointF p2 = new PointF(new Random().nextInt(getMeasuredWidth()), getMeasuredHeight() / 2+new Random().nextInt( getMeasuredHeight() / 2));
PointF p3 = new PointF(new Random().nextInt(getMeasuredWidth()), 0);
pointFS[0] = p0;
pointFS[1] = p1;
pointFS[2] = p2;
pointFS[3] = p3;
return pointFS;
}
public class Bezier implements TypeEvaluator<PointF> {
public PointF pointF1, pointF2,pointF3;
public Bezier(PointF pointF1, PointF pointF2,PointF pointF3) {
this.pointF1 = pointF1;
this.pointF2 = pointF2;
this.pointF3 = pointF3;
}
@Override
public PointF evaluate(float t, PointF startValue, PointF endValue) {
PointF pointF = new PointF();
pointF.x = (1 - t) * (1 - t) * (1 - t) * p0.x
+
3 * (1 - t) * (1 - t) * t * pointF1.x
+
3 * (1 - t) * t * t * pointF2.x
+
t * t * t * pointF3.x;
pointF.y = (1 - t) * (1 - t) * (1 - t) * p0.y
+
3 * (1 - t) * (1 - t) * t * pointF1.y
+
3 * (1 - t) * t * t * pointF2.y
+
t * t * t * pointF3.y;
return pointF;
}
}
二、实现水波一样的 浪呀浪。
public class WaterWaveView extends View {
private Path path = new Path();
private Paint paint ;
int centerLineY ;
int arcY = 50; //震弧
int arcSpeed = 300;//控制点距
int countPoint = 4;
int startPoint;
AccelerateInterpolator
public WaterWaveView(Context context) {
this(context,null);
}
public WaterWaveView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public WaterWaveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void init(){
paint = new Paint(Paint.ANTI_ALIAS_FLAG) ;
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setStrokeWidth(10);
paint.setColor(Color.argb(100,255,0,0));
paint.setAntiAlias(true);
paint.setDither(true);
}
public void setCenterLineY(int progress) {
this.centerLineY = (int) (getMeasuredHeight() * (1 - progress * 1.0 / 100)) ;
postInvalidate();
}
public void random(){
path.reset();
if (Math.abs(startPoint)>=600){
startPoint = -5;
}
startPoint += -5;
postInvalidate();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
centerLineY = getMeasuredHeight()/2 ;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
countPoint = (int) Math.ceil((getMeasuredWidth()+arcSpeed)*1.0 / arcSpeed);
if (centerLineY>0){
path.moveTo(0,centerLineY);
for (int i = 0 ; i<= countPoint;i++){
path.cubicTo(
i * arcSpeed+startPoint,centerLineY,
i * arcSpeed+arcSpeed/2+startPoint,centerLineY+((i % 2 == 0)?-arcY:arcY),
i * arcSpeed+arcSpeed+startPoint,centerLineY
);
}
path.lineTo(getMeasuredWidth(), getMeasuredHeight());
path.lineTo(0, getMeasuredHeight());
path.close();
canvas.drawPath(path,paint);
random();
}
}