一,首先說(shuō)一下姻政,Android 項(xiàng)目中res下的anim 和 animtor 文件夾。
-
anim文件夾
anim文件夾下存放tween animation和frame animation岂嗓;xml文件里只有scale汁展、rotate、translate厌殉、alpha食绿、set五個(gè)標(biāo)簽(默認(rèn)的中心是View的左上角)
使用方法:
1. 加載動(dòng)畫(huà):animation = AnimationUtils.loadAnimation(R.anim.xxx)
2. 設(shè)置動(dòng)畫(huà):mView.setAnimation(animation)
3. 開(kāi)啟動(dòng)畫(huà):mView.startAnimation()
-
animator文件夾
animator文件夾下存放property animation,即屬性動(dòng)畫(huà)公罕,xml文件里有animator器紧、objectAnimator、set三個(gè)標(biāo)簽楼眷。
在XML中:
ObjectAnimator --對(duì)應(yīng)--> <objectAnimator>
AnimatorSet --對(duì)應(yīng)--> <set>
使用方法:
1. 加載動(dòng)畫(huà):animation = AnimatorInflater.loadAnimator(R.animator.xxx)
2. 設(shè)置動(dòng)畫(huà):animation.setTarget(mView)
3. 開(kāi)啟動(dòng)畫(huà):animation .start()
二铲汪,視圖動(dòng)畫(huà)(tween animation)
tween動(dòng)畫(huà)一共有四種動(dòng)畫(huà)效果:
- 平移動(dòng)畫(huà) translate (xml) -->TranslateAnimation (java代碼)
- 縮放動(dòng)畫(huà) scale (xml) -->ScaleAnimation (java代碼)
- 旋轉(zhuǎn)動(dòng)畫(huà) rotate (xml) -->RotateAnimation (java代碼)
- 透明度動(dòng)畫(huà) alpha (xml) -->AlphaAnimation (java代碼)
tween 動(dòng)畫(huà)的坐標(biāo)
tween 的坐標(biāo)體系 ( ↓ Y正方向熊尉;→ X正方形)也是以目標(biāo) view 的坐標(biāo)為參考的。以目標(biāo) view 的左上角為坐標(biāo)原點(diǎn)掌腰。
xml中參數(shù)數(shù)值:
2,% 自身的%為單位
3晕城,%p 以父布局%為單位
注意:tween動(dòng)畫(huà)叠纷,四種操作都不改變其view的屬性。例如:給view添加點(diǎn)擊事件勺择,進(jìn)行平移操作之后创南,該點(diǎn)擊事件仍在原地。
三省核,屬性動(dòng)畫(huà)(Property Animation) -- 通過(guò)動(dòng)畫(huà)的方式改變對(duì)象的屬性了
1稿辙,ObjectAnimator: 常用方法有這些:ofFloat(),ofInt()芳撒,ofObject()邓深,ofArgb(),ofPropertyValuesHolder()笔刹。
/**
* @param target 動(dòng)畫(huà)操作的對(duì)象(可以是任意對(duì)象)
* @param propertyName 表示操作對(duì)象的屬性名字(只要是對(duì)象有的屬性都可以)芥备,任何一切帶有set開(kāi)頭的方法屬性名字。
* 常用的有:
* 平移 translationX舌菜,translationY, X萌壳,Y
* 縮放 scaleX,scaleY
* 旋轉(zhuǎn) rotationX日月, rotationY
* 透明度 alpha袱瓮。
* 也就是說(shuō)控件都有以上setTranslationX(),setScaleX(),setRotationX(),setAlpha() 等方法。
* @param values 動(dòng)畫(huà)過(guò)渡值爱咬。當(dāng)然過(guò)度值可以有一個(gè)到N個(gè)尺借,如果是一個(gè)值的話默認(rèn)這個(gè)值是動(dòng)畫(huà)過(guò)渡值的結(jié)束值。如果有N個(gè)值精拟,動(dòng)畫(huà)就在這N個(gè)值之間過(guò)渡燎斩。
* @return An ObjectAnimator object that is set up to animate between the given values.
*/
ObjectAnimator ofFloat(Object target, String propertyName, float... values)
例如:
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, "alpha", 1.0f, 0.3f, 1.0F);
animator.setDuration(2000);//動(dòng)畫(huà)時(shí)間
animator.setInterpolator(new BounceInterpolator());//動(dòng)畫(huà)插值(有好多種)
animator.setRepeatCount(-1);//設(shè)置動(dòng)畫(huà)重復(fù)次數(shù)--無(wú)限次(ValueAnimator.INFINITE=-1)
animator.setRepeatMode(ValueAnimator.RESTART);//動(dòng)畫(huà)重復(fù)模式
animator.setStartDelay(1000);//動(dòng)畫(huà)延時(shí)執(zhí)行
animator.start();//啟動(dòng)動(dòng)畫(huà)
2,組合動(dòng)畫(huà) -- AnimatorSet
常見(jiàn)方法有:
- after(Animator anim) 將現(xiàn)有動(dòng)畫(huà)插入到傳入的動(dòng)畫(huà)之后執(zhí)行
- after(long delay) 將現(xiàn)有動(dòng)畫(huà)延遲指定毫秒后執(zhí)行
- before(Animator anim) 將現(xiàn)有動(dòng)畫(huà)插入到傳入的動(dòng)畫(huà)之前執(zhí)行
- with(Animator anim) 將現(xiàn)有動(dòng)畫(huà)和傳入的動(dòng)畫(huà)同時(shí)執(zhí)行
//開(kāi)始圖片的透明度從不透明到0.2的透明再到不透明,隨著整個(gè)布局背景的顏色變化的同時(shí)ImageView先向右平移200個(gè)像素蜂绎,
//然后再放大2倍栅表,最后沿著X軸從0到90度再到0度的旋轉(zhuǎn)。
ObjectAnimator animator1 = ObjectAnimator.ofFloat(imageView, "translationX", 0.0f, 200.0f, 0f);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(imageView, "scaleX", 1.0f, 2.0f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(imageView, "rotationX", 0.0f, 90.0f, 0.0F);
ObjectAnimator animator4 = ObjectAnimator.ofFloat(imageView, "alpha", 1.0f, 0.2f, 1.0F);
//組合動(dòng)畫(huà)方式
AnimatorSet set = new AnimatorSet();
((set.play(animator).with(animator1).before(animator2)).before(animator3)).after(animator4);
set.setDuration(5000);
set.start();
3师枣,動(dòng)畫(huà)監(jiān)聽(tīng)器 -- 用來(lái)監(jiān)聽(tīng)不同狀態(tài)下的動(dòng)畫(huà)情況怪瓶。
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
//TODO 動(dòng)畫(huà)開(kāi)始前的操作
/**
* 比如這里可以初始化一些UI
*/
}
@Override
public void onAnimationEnd(Animator animation) {
//TODO 動(dòng)畫(huà)結(jié)束的操作
/**
* 比如這里可以等動(dòng)畫(huà)結(jié)束進(jìn)行一些賬號(hào)登錄或者網(wǎng)絡(luò)數(shù)據(jù)請(qǐng)求等。
*/
}
@Override
public void onAnimationCancel(Animator animation) {
//TODO 動(dòng)畫(huà)取消的操作
}
@Override
public void onAnimationRepeat(Animator animation) {
//TODO 動(dòng)畫(huà)重復(fù)的操作
}
});
如果你不想都寫(xiě)上面的幾個(gè)方法践美,只需要?jiǎng)赢?huà)結(jié)束時(shí)的監(jiān)聽(tīng)洗贰,可以這樣:
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
//TODO 動(dòng)畫(huà)結(jié)束的操作
}
});
AnimatorListenerAdapter的源碼只是一個(gè)實(shí)現(xiàn)了AnimatorListener接口的抽象類而已找岖,你需要監(jiān)聽(tīng)哪種動(dòng)畫(huà)狀態(tài)就重寫(xiě)哪種方法就可以了。
Android系統(tǒng)還給我們提供了一個(gè)更加精確的方法來(lái)時(shí)刻監(jiān)聽(tīng)當(dāng)前動(dòng)畫(huà)的執(zhí)行情況哆姻。那就是addUpdateListener(AnimatorUpdateListener listener)方法了宣增。調(diào)用該方法只需實(shí)現(xiàn)AnimatorUpdateListener接口就可以讀取到動(dòng)畫(huà)的每個(gè)更新值了。
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
//獲取動(dòng)畫(huà)更新值矛缨。
}
});
4爹脾,ValueAnimator
ValueAnimator是屬性動(dòng)畫(huà)中的一個(gè)重要的類,其內(nèi)部使用一種時(shí)間循環(huán)的機(jī)制來(lái)計(jì)算值與值之間的動(dòng)畫(huà)過(guò)渡箕昭,我們只需要將初始值和結(jié)束值提供給ValueAnimator灵妨,并且告訴它動(dòng)畫(huà)所需運(yùn)行的時(shí)長(zhǎng),那么ValueAnimator就會(huì)自動(dòng)幫我們完成從初始值平滑地過(guò)渡到結(jié)束值這樣的效果我們通過(guò)例子來(lái)看看它的用法落竹。ValueAnimator的用法很簡(jiǎn)單:
ValueAnimator animator = ValueAnimator.ofInt(0, 20泌霍,0);
//動(dòng)畫(huà)值的變化,0---> 20 ---->0,常用于自定義View中述召,值的變化
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (int) animation.getAnimatedValue();
Log.e("TAG", "the value is " + value);
}
});
animator.setDuration(1000);//動(dòng)畫(huà)時(shí)間
animator.start();//啟動(dòng)動(dòng)畫(huà)
/**
* 當(dāng)然朱转,還有
* ValueAnimator.ofFloat(0f,10.5f,5.0f,0f);
* ValueAnimator.ofArgb(0x00ffff,0x00ffee);
* ValueAnimator.ofObject() // 比較重要,涉及到了估值器
*/
5积暖,估值器 -- TypeEvaluator
動(dòng)畫(huà)過(guò)程中TypeEvaluator(估值器)的作用:當(dāng)我們ValueAnimator.ofObject()函數(shù)來(lái)做動(dòng)畫(huà)效果的時(shí)候就會(huì)用到估值器了藤为,估值器說(shuō)白了就是用來(lái)確定在動(dòng)畫(huà)過(guò)程中每時(shí)每刻動(dòng)畫(huà)的具體值的;換句話說(shuō)就是確定ValueAnimator.getAnimatedValue()返回的具體對(duì)象類型 ( 當(dāng)我們使用ValueAnimator.ofObject()的時(shí)候夺刑,是一定要去設(shè)置估值器的 ) 缅疟。
所有的估值器都要實(shí)現(xiàn)TypeEvaluator接口,TypeEvaluator接口具體代碼如下遍愿。
public interface TypeEvaluator<T> {
/**
* This function returns the result of linearly interpolating the start and end values, with
* <code>fraction</code> representing the proportion between the start and end values. The
* calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>,
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
* and <code>t</code> is <code>fraction</code>.
*
* @param fraction 表示當(dāng)前這段數(shù)值變化值得比例
* @param startValue 當(dāng)前這段數(shù)值變化的開(kāi)始值
* @param endValue 當(dāng)前這段數(shù)據(jù)變化的結(jié)束值存淫。
* @return A linear interpolation between the start and end values, given the
* <code>fraction</code> parameter.
*/
public T evaluate(float fraction, T startValue, T endValue);
}
簡(jiǎn)單使用如下:
private void startAnimation() {
PointF startPointF = new PointF(0, 0);
PointF endPointF = new PointF(300, 300);
ValueAnimator animator = ValueAnimator.ofObject(new PointEvaluator(), startPointF, endPointF);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//此處得到的返回值類型,由PointEvaluator 決定沼填,為 PointF
PointF pointF = (PointF) animation.getAnimatedValue();
Log.d(TAG, "onAnimationUpdate: " + pointF.x);
x = pointF.x;
//不斷的刷新UI
invalidate();
}
});
animator.setDuration(2000);
animator.start();
}
/**
* 自定義 桅咆,估值器
*/
private class PointEvaluator implements TypeEvaluator<PointF> {
@Override
public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
float resultX = startValue.x + fraction * (endValue.x - startValue.x);
float rexultY = startValue.y + fraction * (endValue.y - startValue.y);
Log.d(TAG, "evaluate: resultX= " + resultX + "\nrexultY=" + rexultY);
return new PointF(resultX, rexultY);
}
}
6,插值器 -- Interpolator
幾種常用的集中插值器(以下圖片源自網(wǎng)絡(luò)):
- AccelerateDecelerateInterpolator開(kāi)始與結(jié)束的地方速率改變比較慢坞笙,在中間的時(shí)候加速轧邪。
- AccelerateInterpolator開(kāi)始的地方速率改變比較慢,然后開(kāi)始加速羞海。
-AnticipateInterpolator開(kāi)始的時(shí)候向后然后向前甩
四、Android 圓形揭露動(dòng)畫(huà)(API>21)
官方介紹
當(dāng)您顯示或隱藏一組UI元素時(shí)曲管,顯示動(dòng)畫(huà)可為用戶提供視覺(jué)連續(xù)性却邓。
/ * @param view 要隱藏或顯示在屏幕上的視圖View.
* @param centerX 剪切圓中心的x坐標(biāo)
* @param centerY 剪切圓中心的y坐標(biāo)
* @param startRadius 剪切圓的起始半徑
* @param endRadius 圓的最終半徑
*/
public static Animator createCircularReveal(View view,
int centerX, int centerY, float startRadius, float endRadius) {
return new RevealAnimator(view, centerX, centerY, startRadius, endRadius);
}
簡(jiǎn)單使用:
Button mRevealBtn = findViewById(R.id.reveal_btn);
int centerX = mRevealBtn.getWidth() / 2;
int centerY = mRevealBtn.getHeight() / 2;
//判斷api是否大于21
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Animator mAnimator = ViewAnimationUtils.createCircularReveal(mRevealBtn, centerX, centerY, Math.max(centerX, centerY), 0);
mAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
//這里可以監(jiān)聽(tīng)到動(dòng)畫(huà)完成的事件;
//可以在這里進(jìn)行g(shù)one的操作
}
});
mAnimator.start();
}