这个时代,新物种正在生长,新边疆正在延伸。做别人的小兵,还是做自己的将军,你选。
- 今天给大家带来的是ValueAnimator的相关用法,下面先给大家看下效果图。
这里我们写了两个位移动画,分别是城市交换动画和日期位移动画,下面我们将通过代码详细介绍下两个动画的具体实现,从而理解valueAnimator的相关使用。
- 左边城市:startCityTextView
- 右边城市:endCityTextView
- 首先获取startCityTextView和endCityTextView的x坐标,因为是水平方向的移动。
- startX:左边城市的横坐标
- endX:右边城市的横坐标
private int startX;
private int endX;
private void getLocation() {
int[] startLocation = new int[2];
startCityTextView.getLocationOnScreen(startLocation);
int[] endLocation = new int[2];
endCityTextView.getLocationOnScreen(endLocation);
startX = startLocation[0];
endX = endLocation[0];
}
final int moveX = endX - startX + endCityTextView.getWidth() - startCityTextView.getWidth();
ValueAnimator startCityAnimation = ValueAnimator.ofInt(0, moveX).setDuration(500);
startCityAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (int) animation.getAnimatedValue();
startCityTextView.layout(startX + value, startCityTextView.getTop(), startX + value + startCityTextView.getWidth(), startCityTextView.getBottom());
}
});
startCityAnimation.start();
int rightMoveX = endX - startX;
ValueAnimator endCityAnimator = ValueAnimator.ofInt(0, rightMoveX).setDuration(500);
endCityAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (int) animation.getAnimatedValue();
endCityTextView.layout(endX - value, endCityTextView.getTop(), endX + endCityTextView.getWidth() - value, endCityTextView.getBottom());
}
});
endCityAnimator.start();
最后需要在动画结束后调换view的位置, 使startCityTextView变为endCityTextView,这样下次动画执行时位置坐标才正确。
endCityAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
TextView flagTextView = startCityTextView;
startCityTextView = endCityTextView;
endCityTextView = flagTextView;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
- isSingleLine:判断是点击的单程还是往返
- 单程:透明度由1变到0,通过重写ObjectAnimator的setEvaluator方法,其中fraction的变化是由0到1
- 往返:透明度从0变到1
ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(rightLayout, View.ALPHA, 0, 1.0f).setDuration(1000);
if (isSingleLine) {
alphaAnimator.setEvaluator(new TypeEvaluator() {
@Override
public Float evaluate(float fraction, Float startValue, Float endValue) {
return 1 - fraction;
}
});
}
alphaAnimator.start();
动画分析:
- screenWidth 屏幕宽度
- 往返:把view从screenWidth+view.getWidth()的位置移动到screenWidth-view.getWidth的位置,移动距离:view.getWidth()
- 单程:把view移出到screenWidth和view.getWidth()之和的位置,移动距离:view.getWidth()
private int getScreenWidth() {
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
return displayMetrics.widthPixels;
}
ValueAnimator animator = ValueAnimator.ofFloat(0, rightLayout.getWidth()).setDuration(500);
animator.setEvaluator(isSingleLine ? new ATFlightEvaluator() : new FloatEvaluator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
int screenWidth = getScreenWidth();
rightLayout.layout(screenWidth - (int) value, rightLayout.getTop(), screenWidth + rightLayout.getWidth() - (int) value, rightLayout.getBottom());
}
});
animator.start();
这里isSingleLine时我们设置其Evaluator为我们自定义的ATFlightEvalutor,实现TypeEvaluator接口并重写其evaluate方法,这样我们获取到动画变化中的value值就是由view.getWidth()—>0变化的。
- startValue: 0
- endValue: view.getWidth()
- fraction: 动画的变化率0—>1
- 其最后返回的值就是我们使用animation.getAnimatedValue()获取的值。
public class ATFlightEvaluator implements TypeEvaluator<Float> {
@Override
public Float evaluate(float fraction, Float startValue, Float endValue) {
return endValue - fraction * (endValue - startValue);
}
}
以上就是我们通过valueAnimator实现的两个小实例,有兴趣的童鞋可以研究下代码,另外有不明白的地方可以在下面留言或者发邮件[email protected]。