本文参考
https://www.jianshu.com/p/fea4d1f6512a
概述
近期碰到曲线动画的实现问题,写本文记录下。
动画类似“剑与远征”游戏的金币动画,动画路径如下图:
思路
- 通过贝塞尔曲线计算出x和y的位置(各个点的位置需要自己微调)
(此部分内容参考此文:https://www.jianshu.com/p/fea4d1f6512a) - 通过ValueAnimator来实现动画
demo如下:
注意:
此demo使用到了屏幕的宽高,因此如果要demo显示正常,需要把状态栏显示透明,把acitionbar去掉。
源码
MainActivity.java
public class MainActivity extends AppCompatActivity {
//ui
private Button btnOne;
private Button btnTwo;
private Button btnAnim;
//data
private int screenHeight;
private int screenWidth;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);//设置透明状态栏
setContentView(R.layout.activity_main);
screenHeight=getResources().getDisplayMetrics().heightPixels;
screenWidth=getResources().getDisplayMetrics().widthPixels;
initViews();
}
private void initViews() {
btnOne = findViewById(R.id.btn_one);
btnTwo = findViewById(R.id.btn_two);
btnAnim = findViewById(R.id.btn_anim);
final ValueAnimator valueAnimator=new ValueAnimator();
valueAnimator.setDuration(2000);
valueAnimator.setObjectValues(new PointF(0, 0));
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF point = (PointF) animation.getAnimatedValue();
btnAnim.setX(point.x);
btnAnim.setY(point.y);
}
});
btnOne.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
valueAnimator.setEvaluator(new TypeEvaluator() {
@Override public Object evaluate(float fraction, Object startValue, Object endValue) {
return BezierUtil.calculateBezierPointForQuadratic(fraction,
new PointF(btnAnim.getLeft(), btnAnim.getTop()),
new PointF(screenWidth, screenHeight/2),
new PointF(btnAnim.getLeft(), screenHeight));
}
});
valueAnimator.start();
}
});
btnTwo.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
valueAnimator.setEvaluator(new TypeEvaluator() {
@Override public Object evaluate(float fraction, Object startValue, Object endValue) {
return BezierUtil.calculateBezierPointForCubic(fraction,
new PointF(btnAnim.getLeft(), btnAnim.getTop()),
new PointF(screenWidth, screenHeight/3),
new PointF(0, screenHeight/3*2),
new PointF(btnAnim.getLeft(), screenHeight));
}
});
valueAnimator.start();
}
});
}
}
BezierUtil.java
public class BezierUtil {
/**
* B(t) = (1 - t)^2 * P0 + 2t * (1 - t) * P1 + t^2 * P2, t ∈ [0,1]
*
* @param t 曲线长度比例
* @param p0 起始点
* @param p1 控制点
* @param p2 终止点
* @return t对应的点
*/
public static PointF calculateBezierPointForQuadratic(float t, PointF p0, PointF p1, PointF p2) {
PointF point = new PointF();
float temp = 1 - t;
point.x = temp * temp * p0.x + 2 * t * temp * p1.x + t * t * p2.x;
point.y = temp * temp * p0.y + 2 * t * temp * p1.y + t * t * p2.y;
return point;
}
/**
* B(t) = P0 * (1-t)^3 + 3 * P1 * t * (1-t)^2 + 3 * P2 * t^2 * (1-t) + P3 * t^3, t ∈ [0,1]
*
* @param t 曲线长度比例
* @param p0 起始点
* @param p1 控制点1
* @param p2 控制点2
* @param p3 终止点
* @return t对应的点
*/
public static PointF calculateBezierPointForCubic(float t, PointF p0, PointF p1, PointF p2,
PointF p3) {
PointF point = new PointF();
float temp = 1 - t;
point.x = p0.x * temp * temp * temp
+ 3 * p1.x * t * temp * temp
+ 3 * p2.x * t * t * temp
+ p3.x * t * t * t;
point.y = p0.y * temp * temp * temp
+ 3 * p1.y * t * temp * temp
+ 3 * p2.y * t * t * temp
+ p3.y * t * t * t;
return point;
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
>
<Button
android:id="@+id/btn_one"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="二阶贝塞尔曲线"
/>
<Button
android:id="@+id/btn_two"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="三阶贝塞尔曲线"
/>
<Button
android:id="@+id/btn_anim"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Anim"
/>
</LinearLayout>
转载:https://blog.csdn.net/Double2hao/article/details/104160061
查看评论