**
1:贝赛尔曲线简介
**
贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线 。 贝塞尔曲线的有趣之处更在于它的“皮筋效应”,也就是说,随着点有规律地移动,曲线将产生皮筋伸引一样的变换,带来视觉上的冲击。
曲线定义: 定义好起始点、终止点(也称锚点)、控制点,控制点可以有多个,每个节点均可编辑。通过调整控制点,贝塞尔曲线的形状会发生变化。
参考博客
以下公式中:B(t)为t时间下 点的坐标;
P0为起点,Pn为终点,Pi为控制点,i为1-n
一阶贝塞尔曲线(线段):
意义:由 P0 至 P1 的连续点, 描述的一条线段
二阶贝塞尔曲线(抛物线):
原理:
由 P0 至 P1 的连续点 Q0,描述一条线段。
由 P1 至 P2 的连续点 Q1,描述一条线段。
由 Q0 至 Q1 的连续点 B(t),描述一条二次贝塞尔曲线。
经验:P1-P0为曲线在P0处的切线。
三阶贝塞尔曲线:
通用公式:
高阶贝塞尔曲线:
4阶曲线:
5阶曲线:
二:利用二阶贝塞尔曲线实现放大缩小的回弹效果
1:计算设计
可以设计如下方式
t为动画时间,start为缩放初始值,end为缩放最终值,control为中间的控制点,最终返回结果是某个时间点对于的需要缩放的值
public float calculateScaleByQuadraticBezier(float t, float start, float control, float end) {
float temp = 1 - t;
return temp * temp * start + 2 * t * temp * control + t * t * end;
}
2:上代码
package com.demo;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity {
private ValueAnimator mCurrentAnimator;
private View mView;
private Button mButton;
private boolean mIsAnimating = false;
private float mFinalScale = 1.3f;//想要放大的值
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mView = findViewById(R.id.test_view);
mButton = findViewById(R.id.test);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mIsAnimating) {
return;
}
if (mView.getScaleX() > 1) {
scaleToNormal(mView);
mButton.setText("放大");
} else {
scaleToBig(mView);
mButton.setText("还原");
}
}
});
}
private void scaleToBig(final View view) {
mCurrentAnimator = ValueAnimator.ofFloat(0, 1);
mCurrentAnimator.setDuration(800);//设置的动画时长
final float start = 1;
final float end = mFinalScale;
final float control = mFinalScale + mFinalScale * 0.3f;//这里的大于end的,最终效果会有一个放大回弹的效果
mCurrentAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
float scale = calculateScaleByQuadraticBezier(value,start,
control,end);
view.setScaleX(scale);
view.setScaleY(scale);
}
});
mCurrentAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
mIsAnimating = false;
}
@Override
public void onAnimationCancel(Animator animation) {
mIsAnimating = false;
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
mIsAnimating = true;
mCurrentAnimator.start();
}
//回到初始状态
private void scaleToNormal(final View view) {
mCurrentAnimator = ValueAnimator.ofFloat(0, 1);
mCurrentAnimator.setDuration(800);
final float start = mFinalScale;
final float end = 1;
final float control = mFinalScale + mFinalScale * 0.3f;
mCurrentAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
float scale = calculateScaleByQuadraticBezier(value,start,
control,end);
view.setScaleX(scale);
view.setScaleY(scale);
}
});
mCurrentAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
mIsAnimating = false;
}
@Override
public void onAnimationCancel(Animator animation) {
mIsAnimating = false;
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
mIsAnimating = true;
mCurrentAnimator.start();
}
public float calculateScaleByQuadraticBezier(float t, float start, float control, float end) {
float temp = 1 - t;
return temp * temp * start + 2 * t * temp * control + t * t * end;
}
}