android image 位移动画_深入理解Android之动画
Android 里動畫從用途上講,可以分為三類View Animation(View動畫)又稱 Tween Animation(補間動畫)、Drawable?Animation(幀動畫)?和 Property Animation(屬性動畫)。 這篇文章,我就介紹一下這三種類型的動畫。
目錄:
(一)View動畫
View動畫是基于View的漸變動畫,只改變了View的繪制效果,View的實際屬性值并未改變。
View動畫的對象是View,它支持4種動畫效果:
TranslateAnimation(平移動畫)
ScaleAnimation(縮放動畫)
RotateAnimation(旋轉動畫)
AlphaAnimation(透明度動畫)
并提供了AnimationSet動畫集合。實現(xiàn)原理是每次繪圖時View所在的ViewGroup中的dispathDraw,流程如下圖:
? ? ? ??
除了這四種典型的動畫效果外,幀動畫本質上也屬于View動畫。但是幀動畫的表現(xiàn)形式和這4種動畫不太一樣,因此通常單拎出來歸為一類。
這四種動畫既可以通過XML來定義,也可以通過代碼來動態(tài)創(chuàng)建。
使用XML之前我們首先需要創(chuàng)建XML文件,路徑為:res/anim/filename.xml。
1.?透明度動畫
代碼實現(xiàn):AlphaAnimation animation = new AlphaAnimation(0, 1);// 透明度0變化到透明度為1
animation.setDuration(1000);// 動畫執(zhí)行時間1s
textView.startAnimation(animation);
XML實現(xiàn):
android:duration="1000"
android:fromAlpha="0"
android:interpolator="@android:anim/accelerate_interpolator"
android:repeatCount="3"
android:fillAfter="true"
android:repeatMode="restart"
android:toAlpha="1" />
2. 旋轉動畫
代碼實現(xiàn):RotateAnimation animation = new RotateAnimation(0, 360, 100, 100);
animation.setDuration(1000);
animation.setFillAfter(true); // 設置保持動畫最后的狀態(tài)
animation.setInterpolator(new AccelerateInterpolator()); // 設置插入器
textView.startAnimation(animation);
還可以通過系統(tǒng)提供參數(shù)來控制動畫
new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
xml實現(xiàn):
android:duration="1000"
android:fromDegrees="0.0"
android:interpolator="@android:anim/linear_interpolator"
android:pivotX="50.0%"
android:pivotY="50.0%"
android:repeatCount="infinite"
android:toDegrees="360.0">
參數(shù)
說明fromDegrees
為動畫起始時的旋轉角度,此角度是當前為0及360,設置其他值則先跳至該角度的位置再由from - to的值: 負則正向轉,正則反向轉
toDegrees
為動畫旋轉到的角度
pivotXType
為動畫在X軸相對于物件位置類型
pivotXValue
為動畫相對于物件的X坐標的開始位置,此值是以本身原始位置為原點,即如設為20%p,則向右移動父控件的20%位移,為負數(shù)則向左移
pivotYType
為動畫在Y軸相對于物件位置類型
pivotYValue
為動畫相對于物件的Y坐標的開始位置,此值是以本身原始位置為原點,即如設為20%p,則向下移動父控件的20%位移,為負數(shù)則向上移
3. 位移動畫
代碼實現(xiàn):TranslateAnimation translateAnimation = new TranslateAnimation(0, 200, 0, 200);
translateAnimation.setDuration(1000);
textView.startAnimation(translateAnimation);
xml實現(xiàn):
android:duration="1000"
android:fillAfter="true"
android:fromXDelta="0"
android:fromYDelta="0"
android:repeatCount="3"
android:toXDelta="200"
android:toYDelta="000">
參數(shù)
說明fromXDelta
為動畫起始時 X坐標上的移動位置
toXDelta
為動畫結束時 X坐標上的移動位置
fromYDelta
為動畫起始時Y坐標上的移動位置
toYDelta
為動畫結束時Y坐標上的移動位置
4. 縮放動畫
代碼實現(xiàn):ScaleAnimation animation = new ScaleAnimation(0,1,0,1);
animation.setDuration(1000);
textView.startAnimation(animation);
縮放動畫也可以設置縮放的中心點
ScaleAnimation animation = new ScaleAnimation(0, 1, 0, 1, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
xml實現(xiàn):
android:duration="1000"
android:fillAfter="true"
android:fillBefore="true"
android:fromXScale="0.0"
android:fromYScale="0.0"
android:interpolator="@android:anim/linear_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="-1"
android:repeatMode="reverse"
android:startOffset="2000"
android:toXScale="1.0"
android:toYScale="1.0">
參數(shù)
說明fromX
為動畫起始時 X坐標上的伸縮尺寸 0.0表示收縮到?jīng)]有
toX
為動畫結束時 X坐標上的伸縮尺寸 1.0表示正常無伸縮
fromY
為動畫起始時Y坐標上的伸縮尺寸 值小于1.0表示收縮
toY
為動畫結束時Y坐標上的伸縮尺寸 值大于1.0表示放大
pivotXType
為動畫在X軸相對于物件位置類型
pivotXValue
為動畫相對于物件的X坐標的開始位置
pivotXType
為動畫在Y軸相對于物件位置類型
pivotYValue
為動畫相對于物件的Y坐標的開始位置
5. anim文件使用
Animation animation = AnimationUtils.loadAnimation(this, R.anim.alpha_anim);
textView.startAnimation(animation);
6. 動畫集合
AnimationSet提供了一個把多個動畫組合成一個組合的機制,并可設置組中動畫的時序關系,如同時播放,順序播放等。
AnimationSet animationSet = new AnimationSet(true);
animationSet.setDuration(1000);
AlphaAnimation alpha=new AlphaAnimation(0,1);
alpha.setDuration(1000);
animationSet.addAnimation(alpha);
TranslateAnimation translate = new TranslateAnimation(100, 200, 0, 200);
translate.setDuration(1000);
animationSet.addAnimation(translate);
textView.startAnimation(animationSet);
7. 動畫監(jiān)聽
對于動畫事件,Android也提供了開始、結束和重復事件的監(jiān)聽方法。
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
8. View動畫的特殊使用
(1)LayoutAnimation
layoutAnimation作用于viewGroup,為ViewGroup制定一個動畫,他的每個子元素都會按照這種動畫出場。這種效果常被用在ListView上。使用步驟如下:
1)定義LayoutAnimation
android:delay="0.5"
android:animationOrder="reverse"
android:animation="@anim/animation_scale">
android:delay? ? ? ? ? ? ?表示子元素開始動畫的時間延遲
android:animationOrder?????????表示子元素動畫的順序,有三個選項:
normal:順序顯示
reverse:表示逆向顯示
random:隨機播放
android:animation????????為子元素指定具體的入場動畫
2)為子元素制定具體的入場動畫
android:fromXScale="0.1"
android:toXScale="1.5"
android:fromYScale="0.1"
android:toYScale="1.5"
android:duration="2000">
3)為GroupView指定LayoutAnimation屬性
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@ id/xlv"
android:layoutAnimation="@anim/animation_layout"
android:background="#fff4f7f9"
android:divider="#ddd"
android:dividerHeight="1.0px"
android:listSelector="#999">
除了在XML文件中進行設置,我們還可以使用代碼來完成:
Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_item);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
listView.setLayoutAnimation(controller);
(2)Transition Animation(過渡動畫)
Transition也是基于屬性動畫的,與屬性動畫不同的是,它是可以實現(xiàn)布局改變的過渡動畫。由于Transition的內容較多,具體請參照
(二)幀動畫
幀動畫就是加載一系列Drawable資源來創(chuàng)建動畫,這種傳統(tǒng)動畫某種程度上就是創(chuàng)建不同圖片序列,順序播放,就像電影膠片。在代碼中定義動畫幀,使用AnimationDrawable類;XML文件能更簡單的組成動畫幀,在res/drawable文件夾,使用采用來定義不同的幀。只能設置的屬性是動畫間隔時間。
android:oneshot="false">
...
然后對組件的屬性(如ImageView的android:src/android:background)直接設置即可。
ImageView iv = findViewById(R.id.image_view);
//iv.setBackgroundResource(R.drawable.drawable_animation);
//獲取背景,并將其強轉成AnimationDrawable
AnimationDrawable animationDrawable = (AnimationDrawable) iv.getBackground();
//判斷是否在運行
if(!animationDrawable.isRunning()){
//開啟幀動畫
animationDrawable.start();
}
注意:幀動畫的使用非常簡單,但是比較容易引起OOM,所以在使用幀動畫時應盡量避免使用過多尺寸較大的圖片。
(三)屬性動畫
屬性動畫的對象除了傳統(tǒng)的View對象,還可以是Object對象,動畫之后,屬性值被實實在在的改變了。因此,屬性動畫能夠通過改變View對象的實際屬性來實現(xiàn)View動畫。任何時候View屬性的改變,View能自動調用invalidate()來刷新。
屬性動畫是在 Android 3.0 開始引入的新的動畫形式,不過說它新只是相對的,它已經(jīng)有好幾年的歷史了,而且現(xiàn)在的項目中的動畫 99% 都是用的它,極少再用到 View Animation 了。屬性動畫不僅可以使用自帶的 API 來實現(xiàn)最常用的動畫,而且通過自定義 View 的方式來做出定制化的動畫。
1. ViewPropertyAnimator
使用方式:
View.animate()?后跟?translationX()?等方法,動畫會自動執(zhí)行。
view.animate().translationX(500);
2. ObjectAnimator
使用方式:
如果是自定義控件,需要添加?setter?/?getter?方法;
用?ObjectAnimator.ofXXX()?創(chuàng)建?ObjectAnimator?對象;
用?start()?方法執(zhí)行動畫。public class SportsView extends View {
float progress = 0;
......
// 創(chuàng)建 getter 方法
public float getProgress() {
return progress;
}
// 創(chuàng)建 setter 方法
public void setProgress(float progress) {
this.progress = progress;
invalidate();
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
......
canvas.drawArc(arcRectF, 135, progress * 2.7f, false, paint);
......
}
}
......
// 創(chuàng)建 ObjectAnimator 對象
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "progress", 0, 65);
// 執(zhí)行動畫
animator.start();
3. 通用功能
(1)setDuration(int duration) 設置動畫時長
(2)setInterpolator(Interpolator interpolator) 設置 Interpolator(插值器)
AccelerateDecelerateInterpolator? 先加速再減速??(默認的?Interpolator)
LinearInterpolator? 勻速
AccelerateInterpolator? 持續(xù)加速
DecelerateInterpolator? 持續(xù)減速直到 0
AnticipateInterpolator? 先回拉一下再進行正常動畫軌跡
OvershootInterpolator? 動畫會超過目標值一些,然后再彈回來
AnticipateOvershootInterpolator? 上面這兩個的結合版:開始前回拉,最后超過一些然后回彈
BounceInterpolator? 在目標值處彈跳
CycleInterpolator? 這個也是一個正弦 / 余弦曲線
FastOutLinearInInterpolator??用貝塞爾曲線持續(xù)加速
LinearOutSlowInInterpolator? 持續(xù)減速,初始速度更高
PathInterpolator? 自定義動畫完成度 / 時間完成度曲線Path interpolatorPath = new Path();
...
// 勻速
interpolatorPath.lineTo(1, 1);
(3)setListener() / ObjectAnimator.addListener()? 設置監(jiān)聽器
參數(shù)類型是?AnimatorListener,所以本質上其實都是一樣的。?AnimatorListener共有 4 個回調方法:
onAnimationStart(Animator animation)
onAnimationEnd(Animator animation)
onAnimationCancel(Animator animation)
onAnimationRepeat(Animator animation)
補充:setUpdateListener() /addUpdateListener()
和上面兩個方法類似,但是這兩個方法雖然名稱和可設置的監(jiān)聽器數(shù)量不一樣,但本質其實都一樣的。它們的參數(shù)都是?AnimatorUpdateListener。它只有一個回調方法:
onAnimationUpdate(ValueAnimator animation)
4.?TypeEvaluator
關于 ObjectAnimator,可以用?ofInt()?來做整數(shù)的屬性動畫和用?ofFloat()?來做小數(shù)的屬性動畫。這兩種屬性類型是屬性動畫最常用的兩種,不過在實際的開發(fā)中,可以做屬性動畫的類型還是有其他的一些類型。當需要對其他類型來做屬性動畫的時候,就需要用到?TypeEvaluator?了。
(1)ArgbEvaluator
TypeEvaluator?最經(jīng)典的用法是使用?ArgbEvaluator?來做顏色漸變的動畫。
ObjectAnimator animator = ObjectAnimator.ofInt(view, "color", 0xffff0000, 0xff00ff00);
animator.setEvaluator(new ArgbEvaluator());
animator.start();
在 Android 5.0 (API 21) 加入了新的方法?ofArgb()。
ObjectAnimator animator = ObjectAnimator.ofArgb(view, "color", 0xffff0000, 0xff00ff00);
animator.start();
(2)自定義 Evaluator
// 自定義 HslEvaluator
private class HsvEvaluator implements TypeEvaluator {
float[] startHsv = new float[3];
float[] endHsv = new float[3];
float[] outHsv = new float[3];
@Override
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
// 把 ARGB 轉換成 HSV
Color.colorToHSV(startValue, startHsv);
Color.colorToHSV(endValue, endHsv);
// 計算當前動畫完成度(fraction)所對應的顏色值
if (endHsv[0] - startHsv[0] > 180) {
endHsv[0] -= 360;
} else if (endHsv[0] - startHsv[0] < -180) {
endHsv[0] = 360;
}
outHsv[0] = startHsv[0] (endHsv[0] - startHsv[0]) * fraction;
if (outHsv[0] > 360) {
outHsv[0] -= 360;
} else if (outHsv[0] < 0) {
outHsv[0] = 360;
}
outHsv[1] = startHsv[1] (endHsv[1] - startHsv[1]) * fraction;
outHsv[2] = startHsv[2] (endHsv[2] - startHsv[2]) * fraction;
// 計算當前動畫完成度(fraction)所對應的透明度
int alpha = startValue >> 24 (int) ((endValue >> 24 - startValue >> 24) * fraction);
// 把 HSV 轉換回 ARGB 返回
return Color.HSVToColor(alpha, outHsv);
}
}
ObjectAnimator animator = ObjectAnimator.ofInt(view, "color", 0xff00ff00);
// 使用自定義的 HslEvaluator
animator.setEvaluator(new HsvEvaluator());
animator.start();
(3)使用不限定類型的屬性做動畫
借助于?TypeEvaluator,屬性動畫就可以通過?ofObject()?來對不限定類型的屬性做動畫了。
1)為目標屬性寫一個自定義的?TypeEvaluator
2)使用?ofObject()?來創(chuàng)建?Animator,并把自定義的?TypeEvaluator?作為參數(shù)填入
private class PointFEvaluator implements TypeEvaluator {
PointF newPoint = new PointF();
@Override
public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
float x = startValue.x (fraction * (endValue.x - startValue.x));
float y = startValue.y (fraction * (endValue.y - startValue.y));
newPoint.set(x, y);
return newPoint;
}
}
ObjectAnimator animator = ObjectAnimator.ofObject(view, "position",
new PointFEvaluator(), new PointF(0, 0), new PointF(1, 1));
animator.start();
5. PropertyValuesHolder
很多時候,我們需要在同一個動畫中改變多個屬性,例如在改變透明度的同時改變尺寸。如果使用?ViewPropertyAnimator,你可以直接用連寫的方式來在一個動畫中同時改變多個屬性。
view.animate()
.scaleX(1)
.scaleY(1)
.alpha(1);
而對于?ObjectAnimator,是不能這么用的。不過你可以使用?PropertyValuesHolder?來同時在一個動畫中改變多個屬性。
PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("scaleX", 1);
PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleY", 1);
PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("alpha", 1);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, holder1, holder2, holder3)
animator.start();
6.?AnimatorSet
有的時候,我們不止需要在一個動畫中改變多個屬性,還會需要多個動畫配合工作,比如,在內容的大小從 0 放大到 100% 大小后開始移動。這種情況使用?PropertyValuesHolder?是不行的,因為這些屬性如果放在同一個動畫中,需要共享動畫的開始時間、結束時間、Interpolator 等一系列的設定,這樣就不能有先后次序地執(zhí)行動畫了。這就需要用到?AnimatorSet?了。
ObjectAnimator animator1 = ObjectAnimator.ofFloat(...);
animator1.setInterpolator(new LinearInterpolator());
ObjectAnimator animator2 = ObjectAnimator.ofInt(...);
animator2.setInterpolator(new DecelerateInterpolator());
AnimatorSet animatorSet = new AnimatorSet();
// 兩個動畫依次執(zhí)行
animatorSet.playSequentially(animator1, animator2);
animatorSet.start();
AnimatorSet?還可以這么用:
// 兩個動畫同時執(zhí)行
animatorSet.playTogether(animator1, animator2);
animatorSet.start();
以及這么用:
// 使用 AnimatorSet.play(animatorA).with/before/after(animatorB)
// 的方式來精確配置各個 Animator 之間的關系
animatorSet.play(animator1).with(animator2);
animatorSet.play(animator1).before(animator2);
animatorSet.play(animator1).after(animator2);
animatorSet.start();
7.?PropertyValuesHolders.ofKeyframe()
除了合并多個屬性和調配多個動畫,你還可以在?PropertyValuesHolder?的基礎上更進一步,通過設置?Keyframe?(關鍵幀),把同一個動畫屬性拆分成多個階段。例如,你可以讓一個進度增加到 100% 后再「反彈」回來。
// 在 0% 處開始
Keyframe keyframe1 = Keyframe.ofFloat(0, 0);
// 時間經(jīng)過 50% 的時候,動畫完成度 100%
Keyframe keyframe2 = Keyframe.ofFloat(0.5f, 100);
// 時間見過 100% 的時候,動畫完成度倒退到 80%,即反彈 20%
Keyframe keyframe3 = Keyframe.ofFloat(1, 80);
PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("progress", keyframe1, keyframe2, keyframe3);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, holder);
animator.start();
總結:「關于復雜的屬性關系來做動畫」,就這么三種:
使用?PropertyValuesHolder?來對多個屬性同時做動畫;
使用?AnimatorSet?來同時管理調配多個動畫;
PropertyValuesHolder?的進階使用:使用?PropertyValuesHolder.ofKeyframe()?來把一個屬性拆分成多段,執(zhí)行更加精細的屬性動畫。
Fighting_初心
發(fā)布了37 篇原創(chuàng)文章 · 獲贊 38 · 訪問量 1萬
私信
關注
來源:https://www.icode9.com/content-4-622551.html
總結
以上是生活随笔為你收集整理的android image 位移动画_深入理解Android之动画的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 无法监控端口_如何使用snmp监控lin
- 下一篇: 星特朗望远镜怎么样_入手曝光评测双筒望远