Android----ObjectAnimator and ValueAnimator

ObjectAnimator extends ValueAnimator

一:相关API
Property Animation就是通过动画的方式改变对象的属性!
Duration动画的持续时间
Time interpolation:时间差值,定义动画的变化率
Repeat count and behavior:重复次数、以及重复模式;可以定义重复多少次;重复时从头开始,还是反向。
Animator sets: 动画集合,你可以定义一组动画,一起执行或者顺序执行!

AnimatorInflater 用户加载属性动画的xml文件
TypeEvaluator 类型估值,主要用于设置动画操作属性的值。

二:实现简单的翻转动画

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:paddingTop="50dp"
android:layout_height="match_parent">

    <ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/cat"/>

</LinearLayout>
public class FristActivity extends Activity {
    ImageView imageView;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_frist);
imageView = (ImageView) findViewById(R.id.image);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                ObjectAnimator.ofFloat(v, "rotationX", 0.0F, 360.0F).setDuration(1000).start();

}
        });
}


}

对于对于ObjectAnimator来说:

ofIntofFloatofObject

2–

//1
ObjectAnimator.ofFloat(v, "rotationX", 0.0F, 360.0F).setDuration(1000).start();
//2
ObjectAnimator.ofFloat(v, "hello world", 0.0F, 360.0F).setDuration(1000).start();

片段1可以正确执行代码,片段2动画没有执行,控制台提示错误信息,截图如下:

Method setHello world() with type float not found on target class class android.widget.ImageView

对于属性值,只设置一个的时候,会认为当前对象该属性的值为开始(getPropName反射获取),然后设置的值为终点。如果设置两个,则一个为开始、一个为结束!
动画更新的过程中,会不断调用setPropName更新元素的属性,所有使用ObjectAnimator更新某个属性,必须得有getter(设置一个属性值的时候)和setter方法!

3–如果需要操作多个对象属性,则需要使用

imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {

        ObjectAnimator animator = ObjectAnimator.ofFloat(v, "rotationX", 0.0F, 360.0F).setDuration(1000);
animator.start();

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
v.setAlpha(0.8f);
v.setScaleX(0.8F);
v.setScaleY(0.8F);
// v.postInvalidate();
              //  v.invalidate();
}
        });
}
});

4–实现一个动画更改多个效果:使用propertyValuesHolder

imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
        PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f,
0f, 1f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX", 1f,
0, 1f);
PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("scaleY", 1f,
0, 1f);
ObjectAnimator.ofPropertyValuesHolder(v, pvhX, pvhY,pvhZ).setDuration(1000).start();
}
});

ValueAnimator:
1–垂直线和抛物线

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

    <ImageView
android:id="@+id/image"
android:layout_width="50dp"
android:layout_height="50dp"
android:scaleType="centerCrop"
android:src="@drawable/cat" />


    <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal">

        <Button
android:id="@+id/one"
android:text="垂直"
android:onClick="verticalRun"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

        <Button
android:id="@+id/two"
android:text="抛物线"
android:onClick="movementView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
    </LinearLayout>

</RelativeLayout>
public class FristActivity extends Activity {
    ImageView imageView;
    private float mScreenHeight;


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_frist);

DisplayMetrics outMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(outMetrics);
mScreenHeight = outMetrics.heightPixels;
imageView = (ImageView) findViewById(R.id.image);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {

            }
        });
}


public void verticalRun(View view) {

        ValueAnimator animator = ValueAnimator.ofFloat(0, this.mScreenHeight
- imageView.getHeight());

animator.setTarget(imageView);
animator.setDuration(1000).start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
imageView.setTranslationY((Float) animation.getAnimatedValue());
}
        });
}


public void movementView(View view) {

        ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setDuration(3000);
valueAnimator.setObjectValues(new PointF(0, 0));
valueAnimator.setEvaluator(new TypeEvaluator<PointF>() {
@Override
public PointF evaluate(float fraction, PointF startValue,
PointF endValue) {
                PointF point = new PointF();
point.x = 200 * fraction * 3;
point.y = 0.5f * 200 * (fraction * 3) * (fraction * 3);
                return point;
}
        });

valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
                PointF point = (PointF) animation.getAnimatedValue();
imageView.setX(point.x);
imageView.setY(point.y);

}
        });
}
}

好处:ValueAnimator并没有设置操作的属性,不需要操作的对象的属性一定要有getter和setter方法,你可以自己根据当前动画的计算值,来操作任何属性!

2–监听动画

ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, "alpha", 0.5f);
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {

    }

@Override
public void onAnimationEnd(Animator animation) {

    }

@Override
public void onAnimationCancel(Animator animation) {
        ViewGroup viewGroup = (ViewGroup) imageView.getParent();
        if (viewGroup != null) {
            viewGroup.removeView(imageView);
}
    }

@Override
public void onAnimationRepeat(Animator animation) {

    }
});
animator.start();

当我们不需要使用这么多的监听方法的时,可以使用AnimatorListenerAdapter:

animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationPause(Animator animation) {
super.onAnimationPause(animation);
}

@Override
public void onAnimationResume(Animator animation) {
super.onAnimationResume(animation);
}
});
public abstract class AnimatorListenerAdapter implements Animator.AnimatorListener,
Animator.AnimatorPauseListener

public static interface AnimatorPauseListener { 
void onAnimationPause(Animator animation);
void onAnimationResume(Animator animation);
}

可以看出:
AnimatorListenerAdapter 空实现了Animator.AnimatorListener并且也实现了
AnimatorPauseListener 的两个方法,所以,比AnimatorListener多两个实现方法!

AnimatorSet的使用:

ObjectAnimator anim1 = ObjectAnimator.ofFloat(imageView, "scaleX",
1.0f, 2f);
ObjectAnimator anim2 = ObjectAnimator.ofFloat(imageView, "scaleY",
1.0f, 2f);
AnimatorSet animSet = new AnimatorSet();
animSet.setDuration(2000);
//两个动画同时执行
animSet.playTogether(anim1, anim2);
//依次执行
animSet.playSequentially(anim1, anim2);
animSet.start();

float cx = imageView.getX();

ObjectAnimator anim1 = ObjectAnimator.ofFloat(imageView, "scaleX",
1.0f, 2f);
ObjectAnimator anim2 = ObjectAnimator.ofFloat(imageView, "scaleY",
1.0f, 2f);
ObjectAnimator anim3 = ObjectAnimator.ofFloat(imageView,
"x", cx, 0f);
ObjectAnimator anim4 = ObjectAnimator.ofFloat(imageView,
"x", cx);

AnimatorSet animSet = new AnimatorSet();
animSet.play(anim1).with(anim2);
animSet.play(anim2).with(anim3);
animSet.play(anim4).after(anim3);
animSet.setDuration(1000);
animSet.start();
playTogether两个动画同时执行,playSequentially依次执行

使用xml创建动画:
1–在res下建立animator文件夹,然后建立相应的xml;

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:propertyName="scaleX"
android:valueFrom="1.0"
android:valueTo="2.0"
android:valueType="floatType">

</objectAnimator>
public class FristActivity extends Activity {
    ImageView imageView;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_frist);
imageView = (ImageView) findViewById(R.id.image);
loadAnimation();
}


private void loadAnimation() {
        Animator animation = AnimatorInflater.loadAnimator(this, R.animator.scalex);
animation.setTarget(imageView);
animation.start();
}

}

—使用
AnimatorInflater.loadAnimator加载动画的资源文件,然后设置目标
2–设置多个属性的时候,需要考虑set:
使用set标签,有一个orderring属性设置为together,sequentially(表示一个接一个执行)。

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

    <objectAnimator
android:duration="1000"
android:propertyName="scaleX"
android:valueFrom="1.0"
android:valueTo="2.0"
android:valueType="floatType"/>

    <objectAnimator
android:duration="1000"
android:propertyName="scaleY"
android:valueFrom="1.0"
android:valueTo="2.0"
android:valueType="floatType"/>
</set>

布局容器动画(Layout Animations):
主要使用LayoutTransition为布局的容器设置动画,当容器中的视图层次发生变化时存在过渡的动画效果!

LayoutTransition transition = new LayoutTransition();      transition.setAnimator(LayoutTransition.CHANGE_APPEARING,              transition.getAnimator(LayoutTransition.CHANGE_APPEARING));      transition.setAnimator(LayoutTransition.APPEARING,              null);      transition.setAnimator(LayoutTransition.DISAPPEARING,              null);      transition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING,              null);    
mGridLayout.setLayoutTransition(transition);  

1–LayoutTransition.APPEARING 当一个View在ViewGroup中出现时,对此View设置的动画
2–LayoutTransition.CHANGE_APPEARING 当一个View在ViewGroup中出现时,对此View对其他View位置造成影响,对其他View设置的动画
3–LayoutTransition.DISAPPEARING 当一个View在ViewGroup中消失时,对此View设置的动画
4–LayoutTransition.CHANGE_DISAPPEARING 当一个View在ViewGroup中消失时,对此View对其他View位置造成影响,对其他View设置的动画
5–LayoutTransition.CHANGE 不是由于View出现或消失造成对其他View位置造成影响,然后对其他View设置的动画。
注意动画到底设置在谁身上,此View还是其他View!

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/id_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">


    <Button
android:id="@+id/add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="addView"
android:text="New Button" />


    <LinearLayout
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:orientation="vertical">

    </LinearLayout>
</LinearLayout>
public class FristActivity extends Activity {
private LinearLayout layout;
    int i = 0;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_frist);

layout = (LinearLayout) findViewById(R.id.layout);
}

public void addView(View view) {
i++;
Button button = new Button(this);
button.setText(i + " ");
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layout.addView(button, params);

button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (i > 0) {
layout.removeViewAt(0);
}
            }
        });
}
}

布局容器中为添加

android:animateLayoutChanges=”true

默认是么有动画效果的。该属性只能用在ViewGroup控件里,表示容器里面布局改变时有默认的动画效果!

该类用于当前布局容器中有View添加,删除,隐藏,显示的时候定义布局容器自身的动画和View的动画。也就是说当一个LinerLayout中隐藏一个view的时候,我们可以自定义 整个LinerLayout容器因为隐藏了view而改变的动画,同时还可以自定义被隐藏的view自己消失时候的动画。你可以先new一个LayoutTransition对象,通过setLayoutTransition()方法将对象设置进一个布局容器ViewGroup中去。代码如下:

private LinearLayout layout;
LayoutTransition layoutTransition;

private void initTransition() {
layoutTransition = new LayoutTransition();
layout.setLayoutTransition(layoutTransition);
}

自定义动画,通过setAnimator() 方法把它们设置进一个 LayoutTransition 对象中去!

ObjectAnimator animator1 = ObjectAnimator.ofFloat(null, "rotationY", 0F, 90F, 0F);
layoutTransition.setAnimator(LayoutTransition.APPEARING, animator1);

listview 的加载过渡动画:

<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/left"
android:animationOrder="normal"
android:delay="30%"></layoutAnimation>

android:delay 子类动画时间间隔 (延迟) 70% 也可以是一个浮点数 如“1.2”等

android:animationOrder=”random”

子类的显示方式 random表示随机
android:animationOrder 的取值有

normal 0 默认 
reverse 1 倒序 
random 2 随机 
android:animation=”@anim/left”

表示孩子显示时的具体动画执行

left.xml:

<class=" hljs xml"><?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="500"
android:fromXDelta="100%"
android:fromYDelta="0"
android:toXDelta="0"
android:toYDelta="0" />
<alpha
android:duration="500"
android:fromAlpha="0"
android:toAlpha="1" />
</set>

通过代码进行获取:

private void initAinm() {
//通过加载XML动画设置文件来创建一个Animation对象;
Animation animation = AnimationUtils.loadAnimation(this, R.anim.left);
//得到一个LayoutAnimationController对象;
LayoutAnimationController lac = new LayoutAnimationController(animation);
lac.setOrder(LayoutAnimationController.ORDER_REVERSE);
//设置控件显示间隔时间;
lac.setDelay(1);
//为ListView设置LayoutAnimationController属性;
listView.setLayoutAnimation(lac);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值