來自:掘金,作者: _yuanhao
鏈接:https://juejin.im/post/5d04610be51d45775a700309#heading-13
引言
眾所周知,一款沒有動(dòng)畫的 app,就像沒有靈魂的肉體,給用戶的體驗(yàn)性很差?,F(xiàn)在的 android 在動(dòng)畫效果方面早已空前的發(fā)展,1.View 動(dòng)畫框架 2.屬性動(dòng)畫框架 3.Drawable 動(dòng)畫。相比后后兩者,View 動(dòng)畫框架在 Android 的最開始就已經(jīng)出現(xiàn),即有著非常容易學(xué)習(xí)的有點(diǎn),卻也有著用法太死的毛病,但對(duì)于初學(xué)者而言,足夠?qū)崿F(xiàn)各種可選的效果了。
組成
對(duì)于 View 的動(dòng)畫框架而言,最常見的有:
- AlphaAnimation(透明度動(dòng)畫)、
- RotateAnimation(旋轉(zhuǎn)動(dòng)畫)、
- ScaleAnimation(縮放動(dòng)畫)、
- TranslateAnimation(平移動(dòng)畫)四種類型。
除此之外還提供了動(dòng)畫集合類(AnimationSet),用于將各種基本動(dòng)畫組合起來進(jìn)行顯示。使用
對(duì)于現(xiàn)在市面上的書籍 ??,基本都是在活動(dòng)代碼中,一步一步設(shè)置透明度,運(yùn)行時(shí)間。來對(duì)控件添加動(dòng)畫框架。所以我這里還是只講 Java 代碼添加那就太無聊了。所以這里我向大家介紹的使用方法,除了基本的以代碼形式添加之外,更有 xml 文件的格式書寫,并在活動(dòng)中直接引用??的騷操作。如果大家對(duì)其他動(dòng)畫方式,比如 Drawable 動(dòng)畫啊,屬性動(dòng)畫啊感興趣,歡迎查看我以后的博文。既然是要在 xml 中配置,那我獻(xiàn)給大家介紹下,xml 中各種屬性的意義:在 /res 下建立 名為 “anim” 的 Directory,將以后的 xml 配置文件都放在該目錄下。<?xml version='1.0' encoding='utf-8'?>
<set xmlns:android='http://schemas.android.com/apk/res/android'
android:shareInterpolator='true'>
<!--透明度更變動(dòng)畫-->
<alpha
android:fromAlpha='float'
android:toAlpha='float' />
<!--縮放動(dòng)畫-->
<scale
android:fromXScale='float'
android:toXScale='float'
android:fromYScale='float'
android:toYScale='float'
android:pivotX='float'
android:pivotY='float' />
<!--平移動(dòng)畫-->
<translate
android:fromXDelta='float'
android:toXDelta='float'
android:fromYDelta='float'
android:toYDelta='float' />
<!--旋轉(zhuǎn)動(dòng)畫-->
<rotate
android:fromDegrees='float'
android:toDegrees='float'
android:pivotX='float'
android:pivotY='float' />
<!--...-->
</set>
下面,我就開始帶領(lǐng)大家,以 ImageView TextView 為例,展示下使用方法,開始發(fā)干貨咯:<?xml version='1.0' encoding='utf-8'?>
<LinearLayout xmlns:android='http://schemas.android.com/apk/res/android'
xmlns:app='http://schemas.android.com/apk/res-auto'
xmlns:tools='http://schemas.android.com/tools'
android:layout_width='match_parent'
android:layout_height='match_parent'
android:gravity='center'
android:orientation='vertical'
tools:context='.AlphaAnimationActivity'>
<!--不建議用 Relativelayout 浪費(fèi)內(nèi)存 哈哈哈-->
<ImageView
android:id='@+id/image'
android:layout_width='300dp'
android:layout_height='200dp'
android:src='@drawable/girl'
android:scaleType='fitXY'
android:alpha='1.0'/>
<!--這里的 alpha 設(shè)置的是最大透明度-->
<TextView
android:id='@+id/text'
android:layout_width='250dp'
android:layout_height='250dp'
android:gravity='center'
android:text='@string/text'
android:background='@color/papayawhip'
android:alpha='0.75'/>
</LinearLayout>
在布局文件中,對(duì)控件設(shè)置 alpha 值,表示最大的透明度在 xml 文件中設(shè)置 alpha 動(dòng)畫,主要分為三個(gè)屬性- toAlpha 表示結(jié)束時(shí)的透明度
- duration 表示變化經(jīng)歷過程所占時(shí)間
在 /res/anim 下建立 alpha_anim.xml 文件<?xml version='1.0' encoding='utf-8'?>
<set xmlns:android='http://schemas.android.com/apk/res/android'>
<alpha
android:fromAlpha='0.0'
android:toAlpha='1.0'
android:duration='1000'/>
</set>
然后直接在活動(dòng)中實(shí)例化 Animate 對(duì)象,引用即可
Animation animation = AnimationUtils.loadAnimation(this, R.anim.alpha_anim);
animation.setFillAfter(false);// 變化之后是永久更改還是恢復(fù)原樣
ImageView imageView = findViewById(R.id.image);
imageView.startAnimation(animation);
TextView textView = findViewById(R.id.text);
textView.startAnimation(animation);
注意這個(gè) setFillAfter 是用于設(shè)定:控件變化之后是永久更改,還是運(yùn)行完了就恢復(fù)原樣運(yùn)行一下,看效果:
縮放動(dòng)畫 -> Scale
在屬性文件(xml)中,scale 的標(biāo)簽主要有一下這幾個(gè)- fromXScale 橫軸方向開始變化時(shí)的大小
- toXScale 橫軸方向變化結(jié)束時(shí)的大小
- fromYScale 縱軸方向開始變化時(shí)的大小
- toYScale 縱軸方向變化結(jié)束時(shí)的大小
- pivotX 按比例確定縮小/放大中心點(diǎn)的橫坐標(biāo)
- pivotY 按比例確定縮小/放大中心點(diǎn)的縱坐標(biāo)
<?xml version='1.0' encoding='utf-8'?>
<set xmlns:android='http://schemas.android.com/apk/res/android'>
<scale
android:duration='2000'
android:fromXScale='1.0'
android:toXScale='0.0'
android:fromYScale='1.0'
android:toYScale='0.0'
android:pivotX='50%'
android:pivotY='50%'/>
</set>
如果你愿意,可以在布局文件中設(shè)置,默認(rèn)開始是的縮放比例:<ImageView
android:id='@+id/scale_image'
android:layout_width='300dp'
android:layout_height='200dp'
android:src='@drawable/girl'
android:scaleType='fitXY'
android:scaleY='0.75'
android:scaleX='1.15'/>
。。。
Animation animation = AnimationUtils.loadAnimation(this, R.anim.scale_anim);
animation.setFillAfter(false);// 變化之后是永久更改還是恢復(fù)原樣
ImageView imageView = findViewById(R.id.scale_image);
imageView.startAnimation(animation);
。。。
平移動(dòng)畫 ->Translate
平移動(dòng)畫相對(duì)其他簡單的屬性動(dòng)畫來說,更為簡單,主要有五個(gè)屬性:
在確定位置屬性的時(shí)候,有三種類型的賦值方法:- 整型值:如:android:fromXDelta='20' 表示自己與左邊界的距離
- 百分比:如:android:fromXDelta='20%' 表示自己與左邊界的距離 和 自己高度的百分比
- 百分比+p:如:android:fromXDelta='20%p' 表示自己與父控件(一般為 ViewGroup )左邊界的距離
<?xml version='1.0' encoding='utf-8'?>
<set xmlns:android='http://schemas.android.com/apk/res/android'>
<translate
android:duration='2000'
android:fromXDelta='20'
android:toXDelta='100'
android:fromYDelta='20'
android:toYDelta='100'/>
</set>
同樣的也可以在布局文件中加以引用,這頂初始值:
<ImageView
android:id='@+id/scale_image'
android:layout_width='300dp'
android:layout_height='200dp'
android:src='@drawable/girl'
android:scaleType='fitXY'
android:translationX='50sp'
android:translationY='20sp'/>
可以看到,設(shè)定了初始位移的 ImageView 相對(duì)與未設(shè)定的 TextView 發(fā)生了偏移
...
Animation animation = AnimationUtils.loadAnimation(this, R.anim.translate_anim);
animation.setFillAfter(false);// 變化之后是永久更改還是恢復(fù)原樣
ImageView imageView = findViewById(R.id.scale_image);
imageView.startAnimation(animation);
...
旋轉(zhuǎn)動(dòng)畫 ->Rotate
對(duì)于旋轉(zhuǎn)動(dòng)畫而言,一切就顯得有趣了起來,我碼字的雙手就顯得疲憊了起來首先還是設(shè)定屬性,對(duì)于旋轉(zhuǎn)動(dòng)畫,基本的屬性有:- toDegrees 動(dòng)畫結(jié)束偏轉(zhuǎn)角度
- pivotX 旋轉(zhuǎn)軸心點(diǎn) X 位置
- pivotY 旋轉(zhuǎn)軸心點(diǎn) Y 位置
同樣的 旋轉(zhuǎn)動(dòng)畫的屬性也有三種設(shè)置方法,但這主要是對(duì)于 pivot 而言,用于確定軸心點(diǎn)位置- 整型值:如:android:pivotX='20' 表示自己與左邊界的距離
- 百分比:如:android:pivotX='20%' 表示自己與左邊界的距離 和 自己高度的百分比
- 百分比+p:如:android:pivotX='20%p' 表示自己與父控件(一般為 ViewGroup )左邊界的距離
<?xml version='1.0' encoding='utf-8'?>
<set xmlns:android='http://schemas.android.com/apk/res/android'>
<rotate
android:duration='2000'
android:fromDegrees='0'
android:toDegrees='+360'
android:pivotX='50%'
android:pivotY='50%'/>
</set>
<ImageView
android:id='@+id/scale_image'
android:layout_width='300dp'
android:layout_height='200dp'
android:src='@drawable/girl'
android:scaleType='fitXY'/>
...
Animation animation = AnimationUtils.loadAnimation(this, R.anim.rotate_anim);
animation.setFillAfter(false);// 變化之后是永久更改還是恢復(fù)原樣
ImageView imageView = findViewById(R.id.scale_image);
imageView.startAnimation(animation);
...
這時(shí)你可能會(huì)揪著我稀疏的秀發(fā)問我,這有趣在哪里??!360度無腦大旋轉(zhuǎn),好了牛逼吹完了,不告述你咋調(diào)的,我先跑了開個(gè)玩笑啦,其實(shí)很簡單,在布局文件中,設(shè)置下傾斜角就行了
<ImageView
android:id='@+id/scale_image'
android:layout_width='300dp'
android:layout_height='200dp'
android:src='@drawable/girl'
android:scaleType='fitXY'
android:rotationX='50'
android:rotationY='20'/>
時(shí)間插值器
好了,到此為止基本動(dòng)畫就結(jié)束了,現(xiàn)在咱來點(diǎn)猛的:對(duì)就是:時(shí)間插值器什么是時(shí)間插值器?我剛學(xué)時(shí)其實(shí)也很懵逼,現(xiàn)在發(fā)覺還是給大家看例子方便使用
<?xml version='1.0' encoding='utf-8'?>
<set xmlns:android='http://schemas.android.com/apk/res/android'
android:interpolator='@android:anim/accelerate_interpolator'>
<alpha
android:fromAlpha='0.0'
android:toAlpha='1.0'
android:duration='5000'/>
</set>
可以看到,變化的數(shù)獨(dú)越來越快,這就是時(shí)間插值器:- android:interpolator='@android:anim/accelerate_interpolator' 設(shè)置動(dòng)畫為加速動(dòng)畫(動(dòng)畫播放中越來越快)
- android:interpolator='@android:anim/decelerate_interpolator' 設(shè)置動(dòng)畫為減速動(dòng)畫(動(dòng)畫播放中越來越慢)
- android:interpolator='@android:anim/accelerate_decelerate_interpolator' 設(shè)置動(dòng)畫為先加速在減速(開始速度最快 逐漸減慢)
- android:interpolator='@android:anim/anticipate_interpolator' 先反向執(zhí)行一段,然后再加速反向回來(相當(dāng)于我們彈簧,先反向壓縮一小段,然后在加速彈出)
- android:interpolator='@android:anim/anticipate_overshoot_interpolator' 同上先反向一段,然后加速反向回來,執(zhí)行完畢自帶回彈效果(更形象的彈簧效果)
- android:interpolator='@android:anim/bounce_interpolator' 執(zhí)行完畢之后會(huì)回彈跳躍幾段(相當(dāng)于我們高空掉下一顆皮球,到地面是會(huì)跳動(dòng)幾下)
- android:interpolator='@android:anim/cycle_interpolator' 循環(huán),動(dòng)畫循環(huán)一定次數(shù),值的改變?yōu)橐徽液瘮?shù):Math.sin(2* mCycles* Math.PI* input)
- android:interpolator='@android:anim/linear_interpolator' 線性均勻改變
- android:interpolator='@android:anim/overshoot_interpolator' 加速執(zhí)行,結(jié)束之后回彈
補(bǔ)間動(dòng)畫 -> Tween animation
摳完了上面每個(gè)的細(xì)節(jié),我們玩波大的,首先我們先定義一個(gè)動(dòng)畫集合:首先們還是,定義一個(gè)屬性文件,但這里我們集合了 縮放 透明度 兩種效果:<?xml version='1.0' encoding='utf-8'?>
<set xmlns:android='http://schemas.android.com/apk/res/android'
android:interpolator='@android:anim/bounce_interpolator' >
<scale
android:duration='500'
android:fromXScale='0.1'
android:fromYScale='0.1'
android:pivotX='50%'
android:pivotY='50%'
android:toXScale='1.0'
android:toYScale='1.0' />
<alpha
android:duration='500'
android:fromAlpha='0'
android:toAlpha='1.0' />
</set>
然后我們?cè)诖a中,對(duì) RecyclerView 設(shè)置它,對(duì)于 RecyclerView Adapter 的寫法這里略去了,設(shè)置的詳細(xì)方法如下:private List<String> list;
private void iniList(){
list = new ArrayList<>();
for (int i = 0 ; i < 30 ; i ++){
list.add(i + ' -- tween 測(cè)試 --');
}
}
private void iniRecyclerView(){
recyclerView = findViewById(R.id.recycler);
GridLayoutManager manager = new GridLayoutManager(this,1);
recyclerView.setLayoutManager(manager);
LayoutAnimationController lac=new LayoutAnimationController(AnimationUtils
.loadAnimation(this, R.anim.in_anim));
lac.setDelay(0.5f);
lac.setOrder(LayoutAnimationController.ORDER_RANDOM);
recyclerView.setLayoutAnimation(lac);
TweenRecyclerAdapter adapter = new TweenRecyclerAdapter(list);
recyclerView.setAdapter(adapter);
}
讓我們運(yùn)行下看看酷炫的效果:
●編號(hào)657,輸入編號(hào)直達(dá)本文
●輸入m獲取到文章目錄