ObjectAnimator,通過設置改變對象的屬性來實現動畫效果,常用的方法有這麼幾種,ofFloat()、ofInt()、ofObject()、ofArgb()、ofPropertyValuesHolder(),具體含義及使用我們在下面的實例中進行講解。
使用ObjectAnimator也是可以輕鬆的實現平移、縮放、旋轉、透明度這幾種動畫效果的,與補間動畫的使用效果是一樣的,那就先來看看這幾種常用的動畫是怎麼實現的。
工程代碼裏就是一個ImageView控件和Activity,
<?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/head"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/head" />
</RelativeLayout>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_object_animator);
head = (ImageView) findViewById(R.id.head);
}
我們這裏就是對ImageView控件head實現動畫效果,本質就是改變head的屬性。
1.平移(translate)
// 平移
private void translateAnimation() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(head, "translationX", 0.0f, 350.0f, 0.0f);
objectAnimator.setDuration(2000);
objectAnimator.setRepeatCount(Animation.INFINITE);
objectAnimator.setRepeatMode(Animation.RESTART);
objectAnimator.start();
}
這段代碼就是用來實現控件的平移,我們來逐行分析這段代碼。
ofFloat方法的函數原型,
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values)
參數含義:
target:動畫操作的對象,我們這裏的操作對象就是ImageView控件head
propertyName:屬性名稱,這裏的"translationX"屬性值意思就是在水平方向移動,如果是"translationY"就是在垂直方向移動,下面講到的其動畫效果也是這個意思,這個屬性值跟我們在xml文件中設置屬性值得名稱是一致的,比如
"android:translationY"。
values:動畫過渡值,過渡值可以有一個到N個,如果是一個值的話,就默認是這個動畫過渡值的結束值,如果有N個值,動畫就在這N個值之間過渡,如本例中有三個過渡值"0.0f, 350.0f, 0f",意思就是從當前位置向右滑到350的位置,再滑到位置0,即初始位置。
然後是動畫的設置,
objectAnimator.setDuration(2000);//動畫的時間間隔
objectAnimator.setRepeatCount(Animation.INFINITE);//重複次數
objectAnimator.setRepeatMode(Animation.RESTART);//重複模式
最後start,動畫就開始執行了
objectAnimator.start();
2.縮放(scale)
// 縮放
private void scaleXAnimation() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(head, "scaleX", 1.0f, 1.5f);
objectAnimator.setDuration(2000);
objectAnimator.setRepeatCount(Animation.INFINITE);
objectAnimator.setRepeatMode(Animation.RESTART);
objectAnimator.start();
}
3.旋轉(rotate)
// 旋轉
private void rotateAnimation() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(head, "rotationX", 0.0f, 90.0f,0.0F);
objectAnimator.setDuration(2000);
objectAnimator.setRepeatCount(Animation.INFINITE);
objectAnimator.setRepeatMode(Animation.RESTART);
objectAnimator.start();
}
4.透明度(alpha)
// 透明度
private void alphaAnimation() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(head, "alpha", 1.0f, 0.3f, 1.0F);
objectAnimator.setDuration(2000);
objectAnimator.setRepeatCount(Animation.INFINITE);
objectAnimator.setRepeatMode(Animation.RESTART);
objectAnimator.start();
}
可能我們也注意到了,在縮放效果的實例中,圖片被放大後就保持當前的狀態,沒有變爲初始的樣子,這是因爲我們在設置過渡值是最終的狀態是1.5f,就放大到1.5倍,並沒有讓它回到原來的狀態,從這點就可以看出,屬性動畫是真真切切的可以改變控件的屬性的,這是與補間動畫的最大不同,補間動畫在動畫結束後都將回到初始狀態。所以說,屬性動畫的使用就顯得更加的靈活。至於上面的其他三個實例,最終回到初始狀態,是因爲我們在設過渡值的時候最終狀態設定的就是初始狀態。
<TextView
android:id="@+id/txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/black"
android:layout_centerInParent="true"
android:textSize="32sp"
android:text="測試顏色變化"/>
int startColor = 0xffff0000;
int endColor = 0xff00ff00;
ObjectAnimator objectAnimator4 = ObjectAnimator.ofObject(txt, "textColor", new TypeEvaluator() {
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
int startInt = (Integer) startValue;
int startA = (startInt >> 24) & 0xff;
int startR = (startInt >> 16) & 0xff;
int startG = (startInt >> 8) & 0xff;
int startB = startInt & 0xff;
int endInt = (Integer) endValue;
int endA = (endInt >> 24) & 0xff;
int endR = (endInt >> 16) & 0xff;
int endG = (endInt >> 8) & 0xff;
int endB = endInt & 0xff;
return (int)((startA + (int)(fraction * (endA - startA))) << 24) |
(int)((startR + (int)(fraction * (endR - startR))) << 16) |
(int)((startG + (int)(fraction * (endG - startG))) << 8) |
(int)((startB + (int)(fraction * (endB - startB))));
}
}, startColor, endColor);
objectAnimator4.setDuration(3000);
objectAnimator4.start();
ofObject方法的原型
public static ObjectAnimator ofObject(Object target, String propertyName, TypeEvaluator evaluator, Object... values)
ObjectAnimator objectAnimator2 = ObjectAnimator.ofArgb(txt, "textColor", 0x000, 0x00FF00);
objectAnimator2.start();
1.setInterpolator():設置動畫插值
控制動畫的變化速率,系統中定義了好幾種Interpolator:
AccelerateDecelerateInterpolator--先加速後減速
AccelerateInterpolator--加速
DecelerateInterpolator--減速
2.setDuration():設置動畫執行時間,動畫時間以毫秒爲單位(ms)
3.setRepeatCount():設置動畫重複次數
大於0的值就代表重複幾次,如果需要無限循環,設爲-1,上面的Animation.INFINITE是系統給的常量,值爲-1,代表無限循環,我們建議使用這個常量,如果設爲0呢?也是執行一次。
4.setRepeatMode():設置動畫重複模式
5.setStartDelay():設置動畫延時操作,也是以毫秒爲單位(ms)
6.setTarget():設置動畫的對象
操作對象,上面的例子中將動畫對象通過ofXXX方傳遞,如果需要改變動畫對象,但動畫效果不變,我們可以使用該方法來設置。
objectAnimator.setTarget(txt);//將動畫對象head變爲txt
7.setEvaluator():設置動畫過度的評估者,即設置TypeEvaluator對象,後面會詳細介紹
after(Animator anim)--將現有動畫插入到傳入的動畫之後執行
after(long delay)--將現有動畫延遲指定毫秒後執行
before(Animator anim)--將現有動畫插入到傳入的動畫之前執行
with(Animator anim)--將現有動畫和傳入的動畫同時執行
playSequentially(Animator... items)--依次執行
private void multiAnimation() {
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(head, "scaleX", 1.0f, 2.5f, 1.0f);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(head, "scaleY", 1.0f, 2.5f, 1.0f);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(head, "rotationX", 0.0f, 90.0f,0.0F);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(objectAnimator1).with(objectAnimator2).with(objectAnimator3);
animatorSet.setDuration(2000);
animatorSet.start();
}
讓動畫同時執行除了使用with方法外,還可以用playTogether方法,
animatorSet.playTogether(objectAnimator1, objectAnimator2, objectAnimator3);
其他幾種就不在演示了。
這種方式只能多個動畫一起執行,不同設置先後順序。
private void multiAnimation2() {
PropertyValuesHolder valuesHolder = PropertyValuesHolder.ofFloat("scaleX", 1.0f, 2.5f, 1.0f);
PropertyValuesHolder valuesHolder1 = PropertyValuesHolder.ofFloat("scaleY", 1.0f, 2.5f, 1.0f);
PropertyValuesHolder valuesHolder2 = PropertyValuesHolder.ofFloat("rotationX", 0.0f, 90.0f,0.0F);
ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(head, valuesHolder, valuesHolder1, valuesHolder2);
objectAnimator.setDuration(2000);
objectAnimator.start();
}
private void viewPropertyAnimator() {
ViewPropertyAnimator animator = head.animate();
animator.translationX(200)
.scaleX(2)
.scaleY(2)
.setDuration(2000)
.start();
}
private void animationListener() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(head, "translationX", 0.0f, 350.0f, 0f);
objectAnimator.setDuration(2000);
objectAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
Log.d("dingfeng", "onAnimationStart......");
}
@Override
public void onAnimationEnd(Animator animation) {
Log.d("dingfeng", "onAnimationEnd......");
}
@Override
public void onAnimationCancel(Animator animation) {
Log.d("dingfeng", "onAnimationCancel......");
}
@Override
public void onAnimationRepeat(Animator animation) {
Log.d("dingfeng", "onAnimationRepeat......");
}
});
objectAnimator.start();
}
可以根據不同需求來實現接口裏面的四個方法,可以根據需要做相應的處理。但有時候你會覺得我不需要監聽動畫的四種狀態,我只需要監聽動畫結束時候的狀態,使用上面的方法就會感覺代碼臃腫了,不過沒關係,Android系統給我們提供了一個更好用的方法,
private void animationListener2() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(head, "translationX", 0.0f, 350.0f, 0f);
objectAnimator.setDuration(2000);
objectAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
Log.d("dingfeng", "onAnimationEnd......");
}
});
objectAnimator.start();
}
可以看出,我們使用了AnimatorListenerAdapter動畫接口適配器代替AnimatorListener接口。其實AnimatorListenerAdapter的源碼只是一個實現了AnimatorListener接口的抽象類而已,
你需要監聽哪種動畫狀態就重寫哪種方法就可以了。
除此之外,AnimatorUpdateListener接口就可以讀取到動畫的每個更新值。
private void animationListener3() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(head, "translationX", 0.0f, 350.0f, 0f);
objectAnimator.setDuration(2000);
objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float)animation.getAnimatedValue();
Log.d("dingfeng", "onAnimationUpdate......"+value);
}
});
objectAnimator.start();
}
一般情況下不太用到這個接口,但是在自定義動畫的時候,通過該接口,可以實現很多複雜的效果。
我們創建兩個動畫文件,一個是旋轉動畫,一個組合動畫
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android='http://schemas.android.com/apk/res/android'
android:duration='2000'
android:propertyName='rotationX'
android:repeatCount="-1"
android:repeatMode="restart"
android:valueFrom='0'
android:valueTo='180'
android:valueType='floatType' />
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android='http://schemas.android.com/apk/res/android'
android:duration='2000'
android:ordering='sequentially'><!--動畫執行順序 sequentially:順序執行;together:同時執行。 -->
<objectAnimator
android:propertyName='translationX'
android:valueFrom='0'
android:valueTo='200'
android:valueType='floatType' />
<set android:ordering='together'>
<objectAnimator
android:propertyName='scaleX'
android:valueFrom='1'
android:valueTo='2'
android:valueType='floatType' />
<objectAnimator
android:propertyName='scaleY'
android:valueFrom='1'
android:valueTo='2'
android:valueType='floatType' />
</set>
</set>
head = (ImageView) findViewById(R.id.head);
Animator animator = AnimatorInflater.loadAnimator(this, R.animator.multi);
animator.setTarget(head);
animator.start();
這樣就OK了,還是很容易的。