這是一篇純粹的實(shí)踐文章毁欣,沒(méi)有解析昭躺,唯一需要提醒的是则果,要保證兩個(gè)小球在垂直方向保持一致的運(yùn)動(dòng)狀態(tài)幔翰。直接上示例圖片(屏幕錄制效果不好)及代碼,代碼中展示了Interpolator西壮、TypeEvaluator和PropertyValuesHolder的簡(jiǎn)單實(shí)用方式
/**
* 通過(guò)兩個(gè)小球同時(shí)落地遗增,演示屬性動(dòng)畫(huà)基本使用
* Author: cuiyan
* Date: 18/5/2 22:39
* Desc:
*/
public class BallsFallDownSimultaneously extends BaseStateViewActivity implements View.OnClickListener {
private View freeFallView;
private View horizontalProjectileMotionView;
// 模擬自由落體
private ObjectAnimator freeFallAnimator;
// 模擬平拋1
private ValueAnimator horizontalProjectileAnimator1;
// 模擬平拋2
private ObjectAnimator horizontalProjectileAnimator2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
init();
}
@Override
public View createContentView(LayoutInflater inflater, ViewGroup contentRoot) {
return inflater.inflate(R.layout.activity_balls_fall_down, contentRoot, false);
}
private void init() {
setText(R.id.tv_title, "兩個(gè)小球同時(shí)落地");
setOnClickListener(R.id.iv_left, this);
setOnClickListener(R.id.tv_reset, this);
setOnClickListener(R.id.tv_start, this);
freeFallView = findViewById(R.id.view_free_fall);
horizontalProjectileMotionView = findViewById(R.id.view_horizontal_projectile_motion);
setContentState(STATE_DATA_CONTENT);
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
if (hasFocus) {
initAnimation();
}
}
private void initAnimation() {
final int verticalDistance = DisplayUtil.getScreenHeight() - freeFallView.getBottom() - DisplayUtil.getStatusBarHeight(this) - DisplayUtil.dp2px(44);
int horizontalDistance = freeFallView.getLeft() - horizontalProjectileMotionView.getRight();
// 自由落體,動(dòng)畫(huà)系統(tǒng)利用反射直接修改view平移屬性
freeFallAnimator = ObjectAnimator.ofFloat(freeFallView, "translationY", 0, verticalDistance);
// 自由落體動(dòng)畫(huà)設(shè)置方式1
freeFallAnimator.setInterpolator(new LinearInterpolator());
freeFallAnimator.setEvaluator(new TypeEvaluator<Float>() {
@Override
public Float evaluate(float fraction, Float startValue, Float endValue) {
return fraction * fraction * (endValue - startValue) + startValue;
}
});
// 自由落體動(dòng)畫(huà)設(shè)置方式2
// freeFallAnimator.setInterpolator(new AccelerateInterpolator());
// 自由落體動(dòng)畫(huà)設(shè)置方式3
// freeFallAnimator.setInterpolator(new TimeInterpolator() {
// @Override
// public float getInterpolation(float input) {
// // 效果等同于freeFallAnimator.setInterpolator(new AccelerateInterpolator());
// return input * input;
// }
// });
// 平拋1款青,需手動(dòng)修改平移屬性
horizontalProjectileAnimator1 = ValueAnimator.ofObject(new MyTypeEvaluator(), new Point(0, 0), new Point(horizontalDistance, verticalDistance));
horizontalProjectileAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Point point = (Point) animation.getAnimatedValue();
horizontalProjectileMotionView.setTranslationX(point.getPointX());
horizontalProjectileMotionView.setTranslationY(point.getPointY());
}
});
horizontalProjectileAnimator1.setInterpolator(new LinearInterpolator());
// 平拋2做修,動(dòng)畫(huà)系統(tǒng)通過(guò)反射直接修改view平移屬性
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("translationX", 0, horizontalDistance);
pvhX.setEvaluator(new TypeEvaluator<Float>() {
@Override
public Float evaluate(float fraction, Float startValue, Float endValue) {
return fraction * (endValue - startValue) + startValue;
}
});
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("translationY", 0, verticalDistance);
pvhY.setEvaluator(new TypeEvaluator<Float>() {
@Override
public Float evaluate(float fraction, Float startValue, Float endValue) {
return fraction * fraction * (endValue - startValue) + startValue;
}
});
horizontalProjectileAnimator2 = ObjectAnimator.ofPropertyValuesHolder(horizontalProjectileMotionView, pvhX, pvhY);
horizontalProjectileAnimator2.setInterpolator(new LinearInterpolator());
}
private void runAnimation() {
AnimatorSet animatorSet = new AnimatorSet();
// animatorSet.play(freeFallAnimator).with(horizontalProjectileAnimator);
// animatorSet.playTogether(freeFallAnimator, horizontalProjectileAnimator1);
animatorSet.playTogether(freeFallAnimator, horizontalProjectileAnimator2);
animatorSet.setDuration(1500);
animatorSet.start();
}
private void reset() {
freeFallView.setTranslationY(0);
horizontalProjectileMotionView.setTranslationX(0);
horizontalProjectileMotionView.setTranslationY(0);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.iv_left: {
finish();
break;
}
case R.id.tv_reset: {
reset();
break;
}
case R.id.tv_start: {
runAnimation();
break;
}
}
}
// 描述小球運(yùn)動(dòng)軌跡坐標(biāo)
private class Point {
private float pointX;
private float pointY;
private Point(float pointX, float pointY) {
this.pointX = pointX;
this.pointY = pointY;
}
private float getPointX() {
return pointX;
}
private void setPointX(float pointX) {
this.pointX = pointX;
}
private float getPointY() {
return pointY;
}
private void setPointY(float pointY) {
this.pointY = pointY;
}
}
// 模擬平拋運(yùn)動(dòng)軌跡的估值器
private class MyTypeEvaluator implements TypeEvaluator<Point> {
@Override
public Point evaluate(float fraction, Point startValue, Point endValue) {
float pointX = fraction * (endValue.getPointX() - startValue.getPointY()) + startValue.getPointX();
float pointY = fraction * fraction * (endValue.getPointY() - startValue.getPointY()) + startValue.getPointY();
return new Point(pointX, pointY);
}
}
}