一鸽斟、概述
- 屬性動(dòng)畫(Property Animation)是在 Android 3.0(API 11)后才提供的一種全新動(dòng)畫模式
- 屬性動(dòng)畫的出現(xiàn)主要是為了彌補(bǔ)補(bǔ)間動(dòng)畫(Tween Animation)的缺陷
- 下面來看一下補(bǔ)間動(dòng)畫的缺陷
1谤绳、 作用對(duì)象的局限
只能夠作用在視圖View上盟猖,即只可以對(duì)一個(gè)Button适揉、TextView玷室、甚至是LinearLayout,或者其它繼承自View的組件進(jìn)行動(dòng)畫操作,但無法對(duì)非View的對(duì)象進(jìn)行動(dòng)畫操作2捕传、 沒有改變View的屬性,只是改變視覺效果
只在屏幕繪制上的動(dòng)畫扩劝,控件的屬性并沒有改變庸论,一個(gè)經(jīng)典的問題就是一個(gè)Button從一個(gè)地方移動(dòng)到另一個(gè)地方,點(diǎn)擊事件還是在原來的地方3今野、拓展性太差
只能寫移動(dòng)葡公、縮放、旋轉(zhuǎn)条霜、漸變四種動(dòng)畫催什,以及這四種動(dòng)畫的組合,一旦遇到相對(duì)復(fù)雜的動(dòng)畫效果宰睡,即超出了上述4種動(dòng)畫效果蒲凶,那么補(bǔ)間動(dòng)畫則無法實(shí)現(xiàn)
二、特點(diǎn)
- 可以用在任意java對(duì)象
- 不只是4種基本變換拆内,還有其他動(dòng)畫效果旋圆,并且可以自定義動(dòng)畫效果
三、工作原理
- 在一定時(shí)間間隔內(nèi)麸恍,通過不斷對(duì)值進(jìn)行改變灵巧,并不斷將該值賦給對(duì)象的屬性搀矫,從而實(shí)現(xiàn)該對(duì)象在該屬性上的動(dòng)畫效果,注意看這里刻肄,屬性動(dòng)畫的本質(zhì)不再是強(qiáng)調(diào)動(dòng)畫本身了瓤球,而是變成了數(shù)值發(fā)生器,不管你想干什么敏弃,屬性動(dòng)畫只關(guān)心生成數(shù)值數(shù)列給你去使用卦羡,這就是屬性動(dòng)畫拓展性的根本,只關(guān)心數(shù)值的生成
-
具體的工作原理如下圖
微信圖片_20180918145035.png
從以上的圖片原理分析有三個(gè)核心類非常重要:AnimatorSet ValueAnimator ObjectAnimator
- AnimatorSet 屬性動(dòng)畫集合麦到,就是把一堆動(dòng)畫放在一起執(zhí)行绿饵,屬性動(dòng)畫的集合提供了幾種非常靈活的動(dòng)畫執(zhí)行方式。
- ValueAnimator 屬性動(dòng)畫的核心:數(shù)值發(fā)生器瓶颠,生成數(shù)值序列的類
- ObjectAnimator 是ValueAnimator的子類拟赊,是對(duì)ValueAnimator操作的封裝,使用起來更簡(jiǎn)便粹淋,一般都是用來對(duì)某一個(gè)對(duì)象的屬性做動(dòng)畫的要门。
四、 ValueAnimator
ValueAnimator 是屬性動(dòng)畫的根基了廓啊,是應(yīng)用最廣廣泛的了,尤其是在自定義 view 中封豪,ValueAnimator類中有幾個(gè)核心的方法
- ValueAnimator ofInt (int... values):返回一個(gè)int型變化的ValueAnimator
(采用默認(rèn)的整型估值器(IntEvaluator)) - ValueAnimator ofFloat (float... values):返回一個(gè)float型變化的ValueAnimator
(采用默認(rèn)的浮點(diǎn)型估值器 (FloatEvaluator)) - ValueAnimator ofArgb (int... values):返回一個(gè)顏色值變化的ValueAnimator谴轮,API LEVEL 21引入。
(采用默認(rèn)的顏色估值器 (ArgbEvaluator)
以上三個(gè)構(gòu)造方法如果傳入了3個(gè)參數(shù) a,b,c ,則是先從a平滑過渡到b,再?gòu)腷平滑過渡到C吹埠,以此類推 - ValueAnimator ofObject (TypeEvaluator evaluator, Object... values):返回一個(gè)object型變化的ValueAnimator第步。
(采用自定義對(duì)象估值器 (TypeEvaluator))
從以上方法的定義上看,主要區(qū)別是四種不同類型的估值器達(dá)到返回不同效果的數(shù)值
還是老一套缘琅,先看使用方法和效果粘都, 使用的方式 分為 XML 設(shè)置 / Java 代碼設(shè)置
4-1、ValueAnimator ofInt (int... values)
方式一刷袍、java代碼設(shè)置
//設(shè)置動(dòng)畫的初始值和結(jié)束值
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 5);
//設(shè)置動(dòng)畫的時(shí)間
valueAnimator.setDuration(500);
//設(shè)置延時(shí)播放
valueAnimator.setStartDelay(500);
//設(shè)置動(dòng)畫播放重復(fù)次數(shù),ValueAnimator.INFINITE=無限重復(fù)
valueAnimator.setRepeatCount(0);
//設(shè)置動(dòng)畫播放模式 ValueAnimator.RESTART=正序播放 ValueAnimator.REVERSE=倒敘播放
valueAnimator.setRepeatMode(ValueAnimator.RESTART);
//將改變的值手動(dòng)付給對(duì)象的屬性值:通過動(dòng)畫的更新監(jiān)聽器實(shí)現(xiàn)
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int animatedValue = (int) animation.getAnimatedValue();
Log.d("DXDD", animatedValue + "");
}
});
valueAnimator.start();
效果圖
從上面可以看出數(shù)值是從0-5的變化翩隧,可以看出并不是均勻分布,呻纹,這就和插值器有關(guān)系了堆生,,看下面源碼
// The time interpolator to be used if none is set on the animation
private static final TimeInterpolator sDefaultInterpolator =
new AccelerateDecelerateInterpolator();
通過源碼看出插值器的速率是始末速率較慢雷酪,中間加速淑仆,如果需要改變動(dòng)畫速率可以通過改變插值器的方法進(jìn)行。從上可以看出插值器和估值器的聯(lián)系哥力≌岬。看下圖分析
方式二、xml代碼設(shè)置
- 步驟1:在路徑 res/animator的文件夾里創(chuàng)建相應(yīng)的動(dòng)畫 .xml文件
- 步驟2:設(shè)置動(dòng)畫參數(shù)
<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"
android:valueFrom="0"
android:valueTo="5"
android:valueType="intType"
android:duration="500"
android:startOffset="500"
android:repeatCount="0"
android:repeatMode="restart"
android:fillBefore="true"
android:interpolator="@android:anim/overshoot_interpolator"
/>
- 使用方法
ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(PropertyAnimaActivity.this, R.animator.values_int);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int animatedValue = (int) animation.getAnimatedValue();
Log.d("DXDD", animatedValue + "");
}
});
animator.start();
效果圖同上,下面結(jié)合手動(dòng)賦值給對(duì)象屬性做個(gè)實(shí)例看看效果
- 實(shí)現(xiàn)的動(dòng)畫效果:圖片寬高放大一倍
//設(shè)置動(dòng)畫的初始值和結(jié)束值(圖片寬度放大一倍)
ValueAnimator valueAnimator = ValueAnimator.ofInt(img_girl.getLayoutParams().width, img_girl.getLayoutParams().width * 2);
//設(shè)置動(dòng)畫的時(shí)間
valueAnimator.setDuration(1000);
//設(shè)置動(dòng)畫播放重復(fù)次數(shù),ValueAnimator.INFINITE=無限重復(fù)
valueAnimator.setRepeatCount(0);
//設(shè)置動(dòng)畫播放模式 ValueAnimator.RESTART=正序播放 ValueAnimator.REVERSE=倒敘播放
valueAnimator.setRepeatMode(ValueAnimator.RESTART);
//設(shè)置插值器
valueAnimator.setInterpolator(new LinearInterpolator());
//將改變的值手動(dòng)付給對(duì)象的屬性值:通過動(dòng)畫的更新監(jiān)聽器實(shí)現(xiàn)
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// 每次值變化時(shí)寞射,將值手動(dòng)賦值給對(duì)象的屬性
img_girl.getLayoutParams().width = (int) animation.getAnimatedValue();
//刷新視圖渔工,即重新繪制,實(shí)現(xiàn)動(dòng)畫效果
img_girl.requestLayout();
}
});
valueAnimator.start();
//設(shè)置動(dòng)畫的初始值和結(jié)束值(圖片高度放大一倍)
ValueAnimator valueAnimator = ValueAnimator.ofInt(img_girl.getLayoutParams().height, img_girl.getLayoutParams().height * 2);
//設(shè)置動(dòng)畫的時(shí)間
valueAnimator.setDuration(1000);
//設(shè)置動(dòng)畫播放重復(fù)次數(shù),ValueAnimator.INFINITE=無限重復(fù)
valueAnimator.setRepeatCount(2);
//設(shè)置動(dòng)畫播放模式 ValueAnimator.RESTART=正序播放 ValueAnimator.REVERSE=倒敘播放
valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
//設(shè)置插值器
valueAnimator.setInterpolator(new LinearInterpolator());
//將改變的值手動(dòng)付給對(duì)象的屬性值:通過動(dòng)畫的更新監(jiān)聽器實(shí)現(xiàn)
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// 每次值變化時(shí)怠惶,將值手動(dòng)賦值給對(duì)象的屬性
img_girl.getLayoutParams().height = (int) animation.getAnimatedValue();
//刷新視圖涨缚,即重新繪制,實(shí)現(xiàn)動(dòng)畫效果
img_girl.requestLayout();
}
});
valueAnimator.start();
效果圖
合并是兩種動(dòng)畫同事播放策治,贯城,感覺代碼有點(diǎn)重復(fù)使用吧,二拐,學(xué)習(xí)完下面的內(nèi)容會(huì)有更簡(jiǎn)單的實(shí)現(xiàn)方法
4-2驰吓、ValueAnimator ofFloat (float... values)使用方法和效果同上,不同的地方是監(jiān)聽返回值是float類型履腋,返回的類型不同主要是因?yàn)槭褂昧瞬煌墓乐灯?估值器在下面會(huì)詳細(xì)介紹)
4-3珊燎、ValueAnimator ofArgb (int... values)
ValueAnimator中的ofArgb()可以幫助我們實(shí)現(xiàn)顏色的漸變效果,Google在API LEVEL 21之后增加了這個(gè)方法ofArgb()遵湖。通過這個(gè)方法我們更容易地實(shí)現(xiàn)顏色演變悔政,通過ofArgb和ArgbEvaluator,我們可以輕松實(shí)現(xiàn)顏色漸變效果
java代碼
//第一種方法
//設(shè)置初始值過度值和結(jié)束值
ValueAnimator argbAnim = ValueAnimator.ofArgb(Color.parseColor("#ff669900"), Color.parseColor("#ff0099cc"), Color.parseColor("#ffff4444"), Color.parseColor("#ff669900"));
//設(shè)置動(dòng)畫時(shí)間
argbAnim.setDuration(2000);
//設(shè)置勻速插值器
argbAnim.setInterpolator(new LinearInterpolator());
//動(dòng)畫監(jiān)聽
argbAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
btn_Argb.setBackgroundColor((Integer) animation.getAnimatedValue());
}
});
argbAnim.start();
//第二種方法
//設(shè)置初始值過度值和結(jié)束值
ValueAnimator argbAnim = ValueAnimator.ofInt(Color.parseColor("#ff669900"), Color.parseColor("#ff0099cc"), Color.parseColor("#ffff4444"), Color.parseColor("#ff669900"));
//設(shè)置動(dòng)畫時(shí)間
argbAnim.setDuration(2000);
//設(shè)置估值器
argbAnim.setEvaluator(new ArgbEvaluator());
//設(shè)置勻速插值器
argbAnim.setInterpolator(new LinearInterpolator());
//動(dòng)畫監(jiān)聽
argbAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
btn_Argb.setBackgroundColor((Integer) animation.getAnimatedValue());
}
});
argbAnim.start();
效果圖如下:(需要向下兼容用第二張方法即可實(shí)現(xiàn))
4-4延旧、ValueAnimator ofObject (TypeEvaluator evaluator, Object... values)
ofObject方法是什么意思呢谋国?我們都知道ofInt和ofFloat都是針對(duì)Int值和Float值的變化,但是迁沫,我們只能控制一個(gè)值的變化芦瘾,但是當(dāng)我們需要實(shí)現(xiàn)多值變化時(shí),它們就不再滿足我們的需求集畅。因?yàn)閮蓚€(gè)屬性的初始值和結(jié)束值不一樣近弟,那么我們就可以將兩個(gè)屬性值封裝到一個(gè)對(duì)象里面,那么初始值的object和結(jié)束值的object就可以包含兩個(gè)屬性不同的初始值和結(jié)束值了挺智,這個(gè)時(shí)候就需要自定義估值TypeEvaluator器達(dá)到效果祷愉。介紹完估值器在進(jìn)行ValueAnimator ofObject示例練習(xí)
五、估值器 (TypeEvaluator)
- 定義:一個(gè)接口
- 作用:設(shè)置 屬性值 從初始值過渡到結(jié)束值 的變化具體數(shù)值
- 應(yīng)用場(chǎng)景: 協(xié)助插值器 實(shí)現(xiàn)非線性運(yùn)動(dòng)的動(dòng)畫效果
- 計(jì)算方式:根據(jù) 插值器計(jì)算出當(dāng)前屬性值改變的百分比 & 初始值 & 結(jié)束值 來計(jì)算 當(dāng)前屬性具體的數(shù)值
(如:動(dòng)畫進(jìn)行了50%(初始值=100逃贝,結(jié)束值=200 )谣辞,那么勻速插值器計(jì)算出了當(dāng)前屬性值改變的百分比是50%,估值器則負(fù)責(zé)計(jì)算當(dāng)前屬性值 = 100 + (200-100)x50% = 150.)=初始值+動(dòng)畫百分比*(結(jié)束值-初始值)
系統(tǒng)默認(rèn)提供了四種估值器沐扳,如果達(dá)不到要求那么就需要我們自定義估值器泥从,需要自定義估值器就需要實(shí)現(xiàn)TypeEvaluator接口,復(fù)寫evaluate()
public interface TypeEvaluator<T> {
/**
*
* @param fraction 插值器getInterpolation()的返回值
* @param startValue 起始值.
* @param endValue 結(jié)束值.
* @return T 賦給動(dòng)畫屬性的具體數(shù)值
*
*/
public T evaluate(float fraction, T startValue, T endValue);
前面介紹過插值器與估值器的關(guān)系沪摄,其實(shí)就事插值器中input 和 fraction關(guān)系:input的值決定了fraction的值:input值經(jīng)過計(jì)算后傳入到插值器的getInterpolation()躯嫉,然后通過實(shí)現(xiàn)getInterpolation()中的邏輯算法纱烘,根據(jù)input值來計(jì)算出一個(gè)返回值,而這個(gè)返回值就是fraction祈餐,那么先來看一個(gè)系統(tǒng)的插值器:浮點(diǎn)型插值器:FloatEvaluator
public class FloatEvaluator implements TypeEvaluator<Number> {
// FloatEvaluator實(shí)現(xiàn)了TypeEvaluator接口
// 重寫evaluate()
public Float evaluate(float fraction, Number startValue, Number endValue) {
// fraction:表示動(dòng)畫完成度(根據(jù)它來計(jì)算當(dāng)前動(dòng)畫的值)
// startValue擂啥、endValue:動(dòng)畫的初始值和結(jié)束值
float startFloat = startValue.floatValue();
return startFloat + fraction * (endValue.floatValue() - startFloat);
//計(jì)算方式:初始值+動(dòng)畫百分比*(結(jié)束值-初始值)
}
- 系統(tǒng)默認(rèn)的估值器都有對(duì)應(yīng)的計(jì)算邏輯,但對(duì)于ValueAnimator.ofObject()帆阳,并沒有系統(tǒng)默認(rèn)實(shí)現(xiàn)哺壶,因?yàn)閷?duì)對(duì)象的動(dòng)畫操作復(fù)雜 & 多樣,系統(tǒng)無法知道如何從初始對(duì)象過度到結(jié)束對(duì)象蜒谤,因此我們需自定義估值器(TypeEvaluator)來告知系統(tǒng)如何進(jìn)行從 初始對(duì)象 過渡到 結(jié)束對(duì)象的邏輯山宾。下面示例實(shí)現(xiàn)一個(gè)加入購(gòu)物車效果的估值器:
效果圖
- 如果需要達(dá)到拋物線效果,就需要自定義貝塞爾曲線數(shù)值變化的估值器
public class PointBezierTypeEvaluator implements TypeEvaluator<PointF> {
PointF control;
PointF mPointF = new PointF();
public PointBezierTypeEvaluator(PointF control) {
this.control = control;
}
@Override
public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
return getBezierPoint(startValue, endValue, control, fraction);
}
/**
* 二次貝塞爾曲線公式
*
* @param start 開始的數(shù)據(jù)點(diǎn)
* @param end 結(jié)束的數(shù)據(jù)點(diǎn)
* @param control 控制點(diǎn)
* @param t float 0-1
* @return 不同t相應(yīng)的PointF
*/
private PointF getBezierPoint(PointF start, PointF end, PointF control, float t) {
mPointF.x = (1 - t) * (1 - t) * start.x + 2 * t * (1 - t) * control.x + t * t * end.x;
mPointF.y = (1 - t) * (1 - t) * start.y + 2 * t * (1 - t) * control.y + t * t * end.y;
return mPointF;
}
- java實(shí)現(xiàn)方式
private void clickView(View view) {
int[] clickCoordinate = new int[2];
int[] parentCoordinate = new int[2];
int[] buyCoordinate = new int[2];
//分別獲取被點(diǎn)擊view鳍徽、父布局资锰、購(gòu)物車在屏幕上的坐標(biāo)
view.getLocationOnScreen(clickCoordinate);
shopping_container.getLocationOnScreen(parentCoordinate);
img_buy.getLocationOnScreen(buyCoordinate);
//創(chuàng)建滑動(dòng)的imageview并添加到父布局中
if (moveImg == null) {
moveImg = new ImageView(this);
moveImg.setImageResource(R.drawable.red_ball);
shopping_container.addView(moveImg);
}
moveImg.setVisibility(View.VISIBLE);
moveImg.setX(clickCoordinate[0] - parentCoordinate[0]);
moveImg.setY(clickCoordinate[1] - parentCoordinate[1]);
//計(jì)算滑動(dòng)imageview的三個(gè)控制點(diǎn)(起點(diǎn)、結(jié)束點(diǎn)阶祭、控制點(diǎn))
PointF startP = new PointF();
PointF endP = new PointF();
PointF controlP = new PointF();
startP.x = clickCoordinate[0] - parentCoordinate[0];
startP.y = clickCoordinate[1] - parentCoordinate[1];
endP.x = buyCoordinate[0] - parentCoordinate[0] + img_buy.getLayoutParams().width / 5;
endP.y = buyCoordinate[1] - parentCoordinate[1] + img_buy.getLayoutParams().width / 5;
controlP.x = endP.x;
controlP.y = startP.y;
//執(zhí)行動(dòng)畫
ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointBezierTypeEvaluator(controlP), startP, endP);
valueAnimator.setDuration(1000);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF pointF = (PointF) animation.getAnimatedValue();
moveImg.setY(pointF.y);
moveImg.setX(pointF.x);
}
}
);
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
moveImg.setVisibility(View.INVISIBLE);
++count;
tv_num.setText(count + "");
ScaleImage(img_buy);
}
});
valueAnimator.start();
}
- 購(gòu)物車動(dòng)畫效果
private void ScaleImage(ImageView img) {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(img, "scaleX", 1f, 0.5f, 1f);
objectAnimator.setDuration(500);
objectAnimator.setInterpolator(new SpringInterpolator());
objectAnimator.start();
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(img, "scaleY", 1f, 0.5f, 1f);
objectAnimator1.setDuration(500);
objectAnimator1.setInterpolator(new SpringInterpolator());
objectAnimator1.start();
}
- 以上就是自定義估值器結(jié)合ValueAnimator.ofObject()實(shí)現(xiàn)購(gòu)物車拋物線效果
- 從購(gòu)物車動(dòng)畫效果代碼看出 ObjectAnimator這個(gè)類的動(dòng)畫實(shí)現(xiàn)方式绷杜,下面詳細(xì)介紹一下這個(gè)類
六、ObjectAnimator
上面說了ObjectAnimator是ValueAnimator的子類濒募,是對(duì)ValueAnimator操作的封裝鞭盟,目的就是讓我們的屬性動(dòng)畫操作更加簡(jiǎn)單,這符合 java 簡(jiǎn)單化的思想瑰剃,大伙仔細(xì)想想懊缺,簡(jiǎn)單好用就是我們碼代碼的終極追求之一啊,下面來看看常用屬性和用法:
6-1 常用的propertyName:
- rotationX 圍繞x軸旋轉(zhuǎn)
- rotationY 圍繞y軸旋轉(zhuǎn)
- rotation 圍繞軸點(diǎn)旋轉(zhuǎn)
- translationX 在x軸方向上平移
- translationY 在y軸方向上平移
- scaleX 在x軸方向縮放
- scaleY 在y軸方向縮放
- alpha 透明度
- width 寬度
- height 高度
6-2 使用方法:
ObjectAnimator animator = ObjectAnimator.ofFloat(testView, "translationX", 100);
animator.setDuration(600);
animator.setRepeatMode(ObjectAnimator.REVERSE);
animator.setRepeatCount(1);
animator.start();
- 這是一個(gè)位移動(dòng)畫培他,像右移動(dòng)100px,需要達(dá)到其他的效果,方法同上遗座,只需修改動(dòng)畫屬性即可舀凛。
七、path動(dòng)畫
5.0版本屬性動(dòng)畫中添加了一個(gè)path動(dòng)畫途蒋,可以讓 view 沿著 path 的路徑做動(dòng)畫
- 代碼
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, View.X, View.Y, path_view.getPath());
animator.setDuration(1000);
animator.setRepeatMode(ObjectAnimator.REVERSE);
animator.setRepeatCount(1);
animator.start();
- 有4個(gè)參數(shù)猛遍,第一個(gè)是目標(biāo) view,后面2個(gè)是需要操作的 view 的位置坐標(biāo)号坡,最后是 path
-
效果圖
path.gif
八懊烤、AnimatorSet 動(dòng)畫集合
8-1在AnimatorSet中給為我們提供了兩個(gè)方法playSequentially和playTogether
- playSequentially表示所有動(dòng)畫依次播放
- playTogether表示所有動(dòng)畫一起開始
playTogether和playSequentially在激活動(dòng)畫后,控件的動(dòng)畫情況與它們無關(guān)宽堆,它們只負(fù)責(zé)定時(shí)激活控件動(dòng)畫腌紧。 playSequentially只有上一個(gè)控件做完動(dòng)畫以后,才會(huì)激活下一個(gè)控件的動(dòng)畫畜隶,如果上一控件的動(dòng)畫是無限循環(huán)壁肋,那下一個(gè)控件就無法做動(dòng)畫了号胚。 - 使用示例:
ObjectAnimator objectAnimator01 = ObjectAnimator.ofArgb(ivImage05, "BackgroundColor",
getResources().getColor(R.color.colorPrimary),
getResources().getColor(R.color.colorAccent),
getResources().getColor(R.color.colorPrimary));
ObjectAnimator objectAnimator02 = ObjectAnimator.ofFloat(ivImage05, "TranslationY", 0, 300, 0);
ObjectAnimator objectAnimator03 = ObjectAnimator.ofFloat(ivImage06, "TranslationY", 0, 400, 0);
ObjectAnimator objectAnimator04 = ObjectAnimator.ofFloat(ivImage07, "TranslationY", 0, 500, 0);
ObjectAnimator objectAnimator05 = ObjectAnimator.ofFloat(ivImage08, "TranslationY", 0, 600, 0);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(objectAnimator01, objectAnimator02, objectAnimator03, objectAnimator04, objectAnimator05);
animatorSet.setDuration(2000);
animatorSet.start();
8-2 AnimatorSet.Builder(自由設(shè)置動(dòng)畫順序)
AnimatorSet.Builder用于實(shí)現(xiàn)playTogether和playSequentially無法實(shí)現(xiàn)的效果,可以實(shí)現(xiàn)非常自由的組合動(dòng)畫浸遗,比如有三個(gè)動(dòng)畫A,B,C想先播放C然后同時(shí)播放A和B猫胁,利用playTogether和playSequentially是沒辦法實(shí)現(xiàn)的,但利用AnimatorSet.Builder卻可以輕易實(shí)現(xiàn)跛锌。
AnimatorSet.Builder常用方法:
方法 | 說明 |
---|---|
public Builder play(Animator anim) | 表示要播放哪個(gè)動(dòng)畫 AnimatorSet中的play方法是獲取AnimatorSet.Builder對(duì)象的唯一途徑 |
public Builder with(Animator anim) | 和前面動(dòng)畫一起執(zhí)行 |
public Builder before(Animator anim) | 執(zhí)行前面的動(dòng)畫后才執(zhí)行該動(dòng)畫 |
public Builder after(Animator anim) | 執(zhí)行先執(zhí)行這個(gè)動(dòng)畫再執(zhí)行前面動(dòng)畫 |
public Builder after(long delay) | 延遲n毫秒之后執(zhí)行動(dòng)畫 |
play(Animator anim)表示當(dāng)前在播放哪個(gè)動(dòng)畫弃秆,另外的with(Animator anim)、before(Animator anim)髓帽、after(Animator anim)都是以play中的當(dāng)前所播放的動(dòng)畫為基準(zhǔn)的菠赚。
當(dāng)play(playAnim)與before(beforeAnim)共用,則表示在播放beforeAnim之前氢卡,先播放playAnim動(dòng)畫锈至;同樣,當(dāng)play(playAnim)與after(afterAnim)共用時(shí)译秦,則表示在在播放afterAnim動(dòng)畫之后峡捡,再播放playAnim動(dòng)畫。
- 使用示例
/**
* 按照自定義順序播放動(dòng)畫
* 首先ivImage09的顏色變化筑悴、位移和ivImage09们拙,同時(shí)發(fā)生
* 等待前面的動(dòng)畫播放完后 ivImage11,ivImage12才開始動(dòng)畫
*
*/
ObjectAnimator objectAnimator01=ObjectAnimator.ofArgb(ivImage09, "BackgroundColor",
getResources().getColor(R.color.colorPrimary),
getResources().getColor(R.color.colorAccent),
getResources().getColor(R.color.colorPrimary));
ObjectAnimator objectAnimator02 = ObjectAnimator.ofFloat(ivImage09, "TranslationY", 0, 300, 0);
ObjectAnimator objectAnimator03 = ObjectAnimator.ofFloat(ivImage10, "TranslationY", 0, 400, 0);
ObjectAnimator objectAnimator04 = ObjectAnimator.ofFloat(ivImage11, "TranslationY", 0, 500, 0);
ObjectAnimator objectAnimator05 = ObjectAnimator.ofFloat(ivImage12, "TranslationY", 0, 600, 0);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(objectAnimator01).with(objectAnimator02).with(objectAnimator03).before(objectAnimator04).before(objectAnimator05);
animatorSet.setDuration(2000);
animatorSet.start();
8-3 PropertyValuesHolder
- 多屬性動(dòng)畫同時(shí)工作管理類阁吝。有時(shí)候我們需要同時(shí)修改多個(gè)屬性砚婆,那就可以用到此類,具體如下:
PropertyValuesHolder a1 = PropertyValuesHolder.ofFloat("alpha", 0f, 1f);
PropertyValuesHolder a2 = PropertyValuesHolder.ofFloat("translationY", 0, viewWidth);
......
ObjectAnimator.ofPropertyValuesHolder(view, a1, a2, ......).setDuration(1000).start();
九突勇、ViewPropertyAnimator
9-1Google官方在Android 3.1系統(tǒng)中補(bǔ)充了ViewPropertyAnimator類装盯,這個(gè)類便是專門為View動(dòng)畫而設(shè)計(jì)的。當(dāng)然這個(gè)類不僅僅是為提供View而簡(jiǎn)單設(shè)計(jì)的甲馋,它存在以下特點(diǎn):
1埂奈、專門針對(duì)View對(duì)象動(dòng)畫而操作的類。
2定躏、提供了更簡(jiǎn)潔的鏈?zhǔn)秸{(diào)用設(shè)置多個(gè)屬性動(dòng)畫账磺,這些動(dòng)畫可以同時(shí)進(jìn)行的。
3痊远、擁有更好的性能垮抗,多個(gè)屬性動(dòng)畫是一次同時(shí)變化,只執(zhí)行一次UI刷新(也就是只調(diào)用一次invalidate,而n個(gè)ObjectAnimator就會(huì)進(jìn)行n次屬性變化碧聪,就有n次invalidate)冒版。
4、每個(gè)屬性提供兩種類型方法設(shè)置scaleX()/scaleXBy()逞姿。
5壤玫、該類只能通過View的animate()獲取其實(shí)例對(duì)象的引用
9-2 每個(gè)屬性豁护,兩種類型方法設(shè)置:
rotationX(20) 改變到某個(gè)值。 旋轉(zhuǎn)到20度欲间。再調(diào)用一次的話楚里,由于已經(jīng)到20度的位置,便不在有變化猎贴。
rotationXBy(20) 改變某個(gè)值的量班缎。 旋轉(zhuǎn)20度。再調(diào)用一次的話她渴,繼續(xù)旋轉(zhuǎn)20度达址,到40度的位置。
9-3常見設(shè)置
view.animate()//獲取ViewPropertyAnimator對(duì)象
//動(dòng)畫持續(xù)時(shí)間
.setDuration(5000)
//透明度
.alpha(0)
.alphaBy(0)
//旋轉(zhuǎn)
.rotation(360)
.rotationBy(360)
.rotationX(360)
.rotationXBy(360)
.rotationY(360)
.rotationYBy(360)
//縮放
.scaleX(1)
.scaleXBy(1)
.scaleY(1)
.scaleYBy(1)
//平移
.translationX(100)
.translationXBy(100)
.translationY(100)
.translationYBy(100)
.translationZ(100)
.translationZBy(100)
//更改在屏幕上的坐標(biāo)
.x(10)
.xBy(10)
.y(10)
.yBy(10)
.z(10)
.zBy(10)
//插值器
.setInterpolator(new BounceInterpolator())//回彈
.setInterpolator(new AccelerateDecelerateInterpolator())//加速再減速
.setInterpolator(new AccelerateInterpolator())//加速
.setInterpolator(new DecelerateInterpolator())//減速
.setInterpolator(new LinearInterpolator())//線性
//動(dòng)畫延遲
.setStartDelay(1000)
//是否開啟硬件加速
.withLayer()
//監(jiān)聽
.setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
Log.i("MainActivity", "run: onAnimationStart");
}
@Override
public void onAnimationEnd(Animator animation) {
Log.i("MainActivity", "run: onAnimationEnd");
}
@Override
public void onAnimationCancel(Animator animation) {
Log.i("MainActivity", "run: onAnimationCancel");
}
@Override
public void onAnimationRepeat(Animator animation) {
Log.i("MainActivity", "run: onAnimationRepeat");
}
})
.setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Log.i("MainActivity", "run: onAnimationUpdate==");
}
})
.withEndAction(new Runnable() {
@Override
public void run() {
Log.i("MainActivity", "run: end");
}
})
.withStartAction(new Runnable() {
@Override
public void run() {
Log.i("MainActivity", "run: start");
}
})
.start();