第二次看屬性動(dòng)畫烁落,結(jié)合兩本書的介紹和郭神的博客來總結(jié)一下熄云。
Android3.0之后的動(dòng)畫系統(tǒng)是 幀動(dòng)畫,屬性動(dòng)畫诉稍,補(bǔ)間動(dòng)畫三足鼎立的局面蝠嘉。
那么他們各自有各自的優(yōu)缺點(diǎn),但是屬性動(dòng)畫是相對(duì)先進(jìn)的技術(shù)杯巨,至少它能解決view移動(dòng)事件不移動(dòng)的情況,它還帶來了更多豐富的效果和更豐富的接口來開發(fā)提升的效率蚤告。
那其實(shí)屬性動(dòng)畫能帶來的不只有這些,具體的好處可以在文末的連接參考郭神的博客服爷,大神寫的更加詳細(xì)杜恰。(同時(shí)本篇里的部分代碼借鑒于郭神的代碼)
1.ValueAnimator
在說屬性動(dòng)畫效果之前必須先討論這個(gè)東西。
ValueAnimator的作用并不是產(chǎn)生動(dòng)畫效果仍源,而是以特定算法來計(jì)算屬性值心褐,通過得到屬性值,Animator就可以對(duì)Object進(jìn)行一系列的動(dòng)畫笼踩,除此之外逗爹,ValueAnimator對(duì)于動(dòng)畫管理,監(jiān)聽器等地方也有所作用嚎于。
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,100);
valueAnimator.setTarget(textView);
valueAnimator.setDuration(1000).start();
valueAnimator.addUpdateListener(new
ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Float f = (Float) animation.getAnimatedValue();
//Log打印f
}
});
我們需要搞到一個(gè)ValueAnimator對(duì)象掘而,那么其實(shí)是通過靜態(tài)工廠類返回對(duì)象挟冠,比如說我們調(diào)用的ofFloat方法,這里傳入一個(gè)可變參數(shù)镣屹,比如說我們給的(0,100)圃郊,
//Android源碼
public static ValueAnimator ofFloat(float... values) {
ValueAnimator anim = new ValueAnimator();
anim.setFloatValues(values);
return anim;
}
當(dāng)我們start這個(gè)動(dòng)畫之后,并給其添加一個(gè)動(dòng)畫的更新監(jiān)聽器女蜈,在終端打印下float的值持舆,你可以看到在1000ms的時(shí)間內(nèi),從0-100的特定規(guī)律變化
如果你想實(shí)現(xiàn)其他形式的變化可以如下:
//0->5->3->10的跳躍性變化
ValueAnimator anim = ValueAnimator.ofFloat(0f, 5f, 3f, 10f);
//整數(shù)型變化
ValueAnimator anim = ValueAnimator.ofInt(0, 100);
當(dāng)然作為動(dòng)畫數(shù)值生成類也是有setRepeat 伪窖, setRepeatMode之類的方法逸寓,主要是對(duì)數(shù)據(jù)進(jìn)行一些花樣的處理(同時(shí)也是滿足不同的動(dòng)畫效果,這些也是在補(bǔ)間動(dòng)畫上有的)
2.ObjectAnimator
到這里才進(jìn)入了我們真正的效果階段覆山,我們真實(shí)能看到效果的竹伸,展現(xiàn)到屏幕上的是ObjectAnimator,那前面說過簇宽,其實(shí)ObjectAnimator是基于ValueAnimator的數(shù)值變化來完成的勋篓,也可以說是ValueAnimator在后面默默地工作,ObjectAnimator才能展示出效果魏割。
同樣的ObjectAnimator的用法也是跟ValueAnimator差不多的譬嚣,通過靜態(tài)工廠返回對(duì)象,通過ofFloat來設(shè)置參數(shù)钞它,最后設(shè)置區(qū)間啟動(dòng)動(dòng)畫拜银。
比如下面的textview的透明度從不透明到全透明到不透明。
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
animator.setDuration(5000);
animator.start();
ofFloat源碼如下
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
anim.setFloatValues(values);
return anim;
}
參數(shù)1:Object目標(biāo)遭垛,也就是我們要實(shí)現(xiàn)動(dòng)畫的東西尼桶,不僅限于view
參數(shù)2:propertyName,屬性名稱锯仪,也就是我們要實(shí)現(xiàn)什么動(dòng)畫
參數(shù)3:可變參數(shù)泵督,主要是實(shí)現(xiàn)的動(dòng)畫的動(dòng)畫參數(shù)
這樣的話一個(gè)簡單的屬性動(dòng)畫就實(shí)現(xiàn)了。
同樣其他動(dòng)畫效果
//旋轉(zhuǎn)360°
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);
animator.setDuration(5000);
animator.start();
//當(dāng)前位置平移-500(左移),然后移動(dòng)回來
float curTranslationX = textview.getTranslationX();
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "translationX", curTranslationX, -500f, curTranslationX);
animator.setDuration(5000);
animator.start()
那么更多的效果也是可以用類似的方法來實(shí)現(xiàn)的庶喜。
具體的有以下幾種:
translationX & translationY :X與Y軸的平移效果
rotationX & rotationY & rotation:圍繞view本身的旋轉(zhuǎn)效果
PrivotX & PrivotY:圍繞著View中心點(diǎn)(默認(rèn))旋轉(zhuǎn)縮放的效果
scaleX & scaleY:中心點(diǎn)縮放的動(dòng)畫
alpha:透明度動(dòng)畫
但是我們?yōu)槭裁茨苡眠@些動(dòng)畫呢幌蚊,還記得在之前說過屬性動(dòng)畫不僅是用于view的,而是可以用于任何地方溃卡,那么這就說明屬性動(dòng)畫設(shè)計(jì)的時(shí)候沒有view限制,我們可以給第二個(gè)參數(shù)傳任何的值進(jìn)去蜒简,但是前提是對(duì)象有g(shù)et/set方法瘸羡,什么意思呢,拿textview舉例搓茬,我們?cè)趖extview的源碼中可以找到setAlpha()方法如下:
public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
ensureTransformationInfo();
if (mTransformationInfo.mAlpha != alpha) {
// Report visibility changes, which can affect children, to accessibility
if ((alpha == 0) ^ (mTransformationInfo.mAlpha == 0)) {
notifySubtreeAccessibilityStateChangedIfNeeded();
}
mTransformationInfo.mAlpha = alpha;
if (onSetAlpha((int) (alpha * 255))) {
mPrivateFlags |= PFLAG_ALPHA_SET;
// subclass is handling alpha - don't optimize rendering cache invalidation
invalidateParentCaches();
invalidate(true);
} else {
mPrivateFlags &= ~PFLAG_ALPHA_SET;
invalidateViewProperty(true, false);
mRenderNode.setAlpha(getFinalAlpha());
}
}
}
具體代碼在這里不解釋犹赖,正是因?yàn)橛辛诉@個(gè)方法队他,我們的alpha動(dòng)畫才可以生效,所以你大概可以明白峻村,當(dāng)我們的object木有PropertyName的get/set方法的時(shí)候麸折,我們是沒法進(jìn)行動(dòng)畫實(shí)現(xiàn)的。
那么其實(shí)現(xiàn)在你就明白了屬性動(dòng)畫的強(qiáng)大了粘昨,它給予你非常大的自定義空間垢啼,你可以給任何對(duì)象添加你想要的實(shí)現(xiàn)。
然后如果你想實(shí)現(xiàn)一個(gè)動(dòng)畫監(jiān)聽器的話
objectAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
//動(dòng)畫開始
}
@Override
public void onAnimationEnd(Animator animation) {
//動(dòng)畫結(jié)束
}
@Override
public void onAnimationCancel(Animator animation) {
//動(dòng)畫取消
}
@Override
public void onAnimationRepeat(Animator animation) {
//動(dòng)畫重復(fù)
}
});
當(dāng)然系統(tǒng)還提供了適配器來解決只選擇必要的方法重寫的功能张肾。
objectAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationRepeat(Animator animation) {
super.onAnimationRepeat(animation);
}
});
3.組合動(dòng)畫
雖然我們已經(jīng)可以實(shí)現(xiàn)簡單的動(dòng)畫芭析,但是產(chǎn)品總是會(huì)有很多神奇的想法,今天實(shí)現(xiàn)這么個(gè)動(dòng)畫吞瞪,明天實(shí)現(xiàn)這個(gè)動(dòng)畫馁启,各種奇怪的需求,你不得不尋找解決辦法芍秆,但是在屬性動(dòng)畫中惯疙,官方也給了相應(yīng)API來實(shí)現(xiàn),可以說是很不錯(cuò)的妖啥。
實(shí)現(xiàn)組合動(dòng)畫功能主要需要借助AnimatorSet這個(gè)類霉颠,這個(gè)類提供了一個(gè)play()方法,如果我們向這個(gè)方法中傳入一個(gè)Animator對(duì)象(ValueAnimator或ObjectAnimator)將會(huì)返回一個(gè)AnimatorSet.Builder的實(shí)例
那么AnimatorSet.Builder的源碼如下:
public class Builder {
private Node mCurrentNode;
Builder(Animator anim) {
mDependencyDirty = true;
mCurrentNode = getNodeForAnimation(anim);
}
public Builder with(Animator anim) {
Node node = getNodeForAnimation(anim);
mCurrentNode.addSibling(node);
return this;
}
public Builder before(Animator anim) {
mReversible = false;
Node node = getNodeForAnimation(anim);
mCurrentNode.addChild(node);
return this;
}
public Builder after(Animator anim) {
mReversible = false;
Node node = getNodeForAnimation(anim);
mCurrentNode.addParent(node);
return this;
}
public Builder after(long delay) {
// setup dummy ValueAnimator just to run the clock
ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
anim.setDuration(delay);
after(anim);
return this;
}
}
Builder是構(gòu)建者迹栓,每次調(diào)用都會(huì)返回builder自身用于繼續(xù)構(gòu)建掉分,這四個(gè)方法分別是:
- after(Animator anim) 將現(xiàn)有動(dòng)畫插入到傳入的動(dòng)畫之后執(zhí)行
- after(long delay) 將現(xiàn)有動(dòng)畫延遲指定毫秒后執(zhí)行
- before(Animator anim) 將現(xiàn)有動(dòng)畫插入到傳入的動(dòng)畫之前執(zhí)行
- with(Animator anim) 將現(xiàn)有動(dòng)畫和傳入的動(dòng)畫同時(shí)執(zhí)行
通過這樣我們就可以控制動(dòng)畫播放順序,來實(shí)現(xiàn)想要的效果克伊。
ObjectAnimator animator1 = ObjectAnimator.ofFloat(textView,"translationX",0.0f,200.0f,0f);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(textView,"scaleX",1.0f,2.0f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(textView,"rotationX",0.0f,90.0f,0f);
AnimatorSet set = new AnimatorSet();
set.setDuration(1000);
set.play(animator1).with(animator2).after(animator3);
set.start();
4.XML實(shí)現(xiàn)
在以前實(shí)現(xiàn)動(dòng)畫效果的時(shí)候我們可以用xml來實(shí)現(xiàn)酥郭,當(dāng)然屬性動(dòng)畫也不例外,有了xml代碼我們可以節(jié)省時(shí)間空間愿吹,很方便的調(diào)用不从,會(huì)達(dá)到一個(gè)代碼的復(fù)用,使用之前首先在res中建立animator(這個(gè)是為屬性動(dòng)畫準(zhǔn)備的)文件夾犁跪,那么在XML文件中我們一共可以使用如下三種標(biāo)簽:
<animator> 對(duì)應(yīng)代碼中的ValueAnimator
<objectAnimator> 對(duì)應(yīng)代碼中的ObjectAnimator
<set> 對(duì)應(yīng)代碼中的AnimatorSet
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="sequentially" >
<objectAnimator
android:duration="2000"
android:propertyName="translationX"
android:valueFrom="-500"
android:valueTo="0"
android:valueType="floatType" >
</objectAnimator>
<set android:ordering="together" >
<objectAnimator
android:duration="3000"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="360"
android:valueType="floatType" >
</objectAnimator>
<set android:ordering="sequentially" >
<objectAnimator
android:duration="1500"
android:propertyName="alpha"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType" >
</objectAnimator>
<objectAnimator
android:duration="1500"
android:propertyName="alpha"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType" >
</objectAnimator>
</set>
</set>
</set>
這里搬郭神的一段代碼來椿息,這是使用xml來完成一個(gè)動(dòng)畫集合的效果,當(dāng)然如果寫單個(gè)動(dòng)畫只需要寫
<objectAnimator
android:duration="1500"
android:propertyName="alpha"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType" >
</objectAnimator>
一部分坷衍。
在java中的調(diào)用是這樣的
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_file);
animator.setTarget(view);
animator.start();
首先加載動(dòng)畫文件寝优,綁定視圖,最后啟動(dòng)動(dòng)畫枫耳。
屬性動(dòng)畫的介紹就這么多乏矾,肯定不如郭神講的詳細(xì),下面也給了郭神的文章鏈接,更多的請(qǐng)?jiān)L問钻心。
參考:http://blog.csdn.net/guolin_blog/article/details/43536355