补间动画
通过平移,旋转,渐变,缩放等操作实现动画效果。和属性动画不同的是,属性动画会改变View的位置,而补间动画没有改变View的真正位置。如下:
xml布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.yeliang.animation.MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="startAnimation"
android:text="Hello World!"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="210dp"
android:id="@+id/button" />
</RelativeLayout>
Activity
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void startAnimation(View view){
Animation animation = AnimationUtils.loadAnimation(this,R.anim.translate);
animation.start();
view.startAnimation(animation);
}
}
xml动画
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fillAfter="true"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="30%p"
//表示屏幕的30%
android:toYDelta="30%p">
</translate>
每次点击button最开始的位置才会响应,点击button移动后的位置并没有反应。运行效果:
属性动画
修改Activity中的代码后
1 在x轴方向上平移
int position = 0;
public void startAnimation(View view) {
position += 100;
//每次平移的坐标为在x方向上加100
view.setTranslationX(position);
}
点击button每次移动后的位置,运行效果:
2 在x轴方向上相对于原始位置平移
public void startAnimation(View view) {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, "translationX", 0f, 300f);
objectAnimator.setDuration(1000);
objectAnimator.start();
}
3 在y轴方向上相对于原始位置平移
public void startAnimation(View view) {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, "translationY", 0f, 300f);
objectAnimator.setDuration(1000);
objectAnimator.start();
}
4 围绕x轴翻转
public void startAnimation(View view) {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, "rotationX", 0f, 360f);
objectAnimator.setDuration(1000);
objectAnimator.start();
}
5 通过ObjectAnimator,动画执行过程中会多次回调AnimatorUpdateListener接口中的onAnimationUpdate()方法。
public void startAnimation(final View view) {
//可以看出 第三个参数即使不传也能执行默认动画效果
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, "woca", 0f, 100f);
objectAnimator.setDuration(500);
objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
animation.getAnimatedFraction();
float value = (float) animation.getAnimatedValue();
view.setScaleX(0.5f + value / 200); //0.5f-1.5f
view.setScaleY(0.5f + value / 200); //0.5f-1.5f
}
});
//动画执行状态的回调,这里未实现。
objectAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
});
objectAnimator.start();
}
怎么样,这效果有没有突然菊花一紧的感觉?
6 通过ValueAnmator,动画执行过程中会多次回调AnimatorUpdateListener接口中的onAnimationUpdate()方法。
public void startAnimation(final View view) {
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 200f);
valueAnimator.setDuration(500);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
animation.getAnimatedFraction();//动画执行百分比 这里没用到
float value = (float) animation.getAnimatedValue();
view.setScaleX(0.5f + value / 400); //0.5f-1
view.setScaleY(0.5f + value / 400); //0.5f-1
}
});
valueAnimator.start();
}
7 ObjectAnimator和PropertyValuesHolder来实现多个动画的组合
public void startAnimation(final View view) {
PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("alpha", 1f, 0.7f, 1f);
PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0.7f, 1f);
PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0.7f, 1f);
PropertyValuesHolder holder4 = PropertyValuesHolder.ofFloat("translationX",0f, 300f);
ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(view, holder1, holder2, holder3, holder4);
objectAnimator.setDuration(1000);
objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float animatedValue = (float) animation.getAnimatedValue();
long playTime = animation.getCurrentPlayTime();
Log.i("MainActivity", "animatedValue=" + animatedValue + "-----playTime=" + playTime);
}
});
objectAnimator.start();
}
根据下面的打印结果可以得出,动画从1-0.7和从0.7到1执行的事件相等。也就是说从一个动画过程到另一个动画过程经历的时间相等。
MainActivity: animatedValue=0.71507335-----playTime=518
MainActivity: animatedValue=1.0-----playTime=1006
8 通过ObjectAnimator和AnimatorSet实现动画的组合
public void startAnimation(final View view) {
ObjectAnimator animator1 = ObjectAnimator.ofFloat(view,"alpha",1f,0.7f,1f);
ObjectAnimator animator2 =ObjectAnimator.ofFloat(view,"scaleX",1f,0.7f,1f);
ObjectAnimator animator3 =ObjectAnimator.ofFloat(view,"scaleY",1f,0.7f,1f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(1000);
// animatorSet.play(animator1);//执行单个动画
animatorSet.playTogether(animator1,animator2,animator3);//同时执行
// animatorSet.playSequentially(animator1,animator2,animator3);//依次执行
animatorSet.start();
}
9 通过设置插值器,来获得某一瞬时时间点的坐标
public void startAnimation(final View view) {
ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setDuration(4000);
valueAnimator.setObjectValues(new PointF(0, 0));
//插值器
valueAnimator.setEvaluator(new TypeEvaluator<PointF>() {
@Override
public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
//拿到每一个时间点的坐标
PointF pointF = new PointF();
pointF.x = 100f * (fraction * 4);
pointF.y = 0.5f * 50f * (fraction * 4) * (fraction * 4);
return pointF;
}
});
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF pointF = (PointF) animation.getAnimatedValue();
//这是View的坐标
view.setX(pointF.x);
view.setY(pointF.y);
}
});
valueAnimator.start();
}
加速器效果
1 匀加速
public void startAnimation(final View view) {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, "translationY", 0f, 400f);
objectAnimator.setDuration(500);
//设置加速器
objectAnimator.setInterpolator(new AccelerateInterpolator(3));
objectAnimator.start();
}
2 加速度先变大再变小
objectAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
3 向上有个回弹效果
objectAnimator.setInterpolator(new AnticipateInterpolator(8));
4 向下有个回弹 下落到最后时再向前
objectAnimator.setInterpolator(new OvershootInterpolator());
5 上下回弹多次
oa.setInterpolator(new CycleInterpolator(4));
6 模仿物理回弹效果
objectAnimator.setInterpolator(new BounceInterpolator());