一般來(lái)說(shuō),當(dāng)內(nèi)容更換時(shí),有動(dòng)畫(huà)的話會(huì)更好過(guò)渡,用戶也會(huì)體驗(yàn)較好。有三種比較常見(jiàn)的動(dòng)畫(huà)用于隱藏或顯示內(nèi)容:Circle Reveal動(dòng)畫(huà)、淡入淡出效果、卡片翻轉(zhuǎn)效果。
下面將分別介紹這三種常見(jiàn)的動(dòng)畫(huà)效果:
淡入淡出動(dòng)畫(huà)
淡入淡出動(dòng)畫(huà)一般是一個(gè)View在漸漸消失,另一個(gè)View同時(shí)在漸漸出現(xiàn)。
先看效果,如下圖:

可以看到效果是一個(gè)文本漸漸出現(xiàn),loading漸漸消失。
創(chuàng)建xml布局
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".animation.CrossFadeActivity">
<ScrollView
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
style="?android:textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:lineSpacingMultiplier="1.2"
android:padding="16dp"
android:text="@string/large_text"/>
</ScrollView>
<ProgressBar
android:id="@+id/loading_spinner"
style="?android:progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
</FrameLayout>
代碼實(shí)現(xiàn)動(dòng)畫(huà)
class CrossFadeActivity : AppCompatActivity() {
private var mShortAnimationDuration: Int = 5000
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_cross_fade)
crossFade()
}
private fun crossFade() {
content.apply {
visibility = View.VISIBLE
alpha = 0f
animate().alpha(1.0f)
.setDuration(mShortAnimationDuration.toLong())
.withEndAction {
content.visibility = View.VISIBLE
}.start()
}
loading_spinner.animate()
.alpha(0.0f)
.setDuration(mShortAnimationDuration.toLong())
.withEndAction {
loading_spinner.visibility = View.GONE
}.start()
}
}
這里使用的屬性動(dòng)畫(huà),初始時(shí)內(nèi)容alpha=0,漸漸變?yōu)?,而loading的alpha則由1變?yōu)?。喂了看出效果因此,設(shè)置了5s。
卡片翻轉(zhuǎn)動(dòng)畫(huà)
先看效果:

這里采用自定義Fragment的專場(chǎng)動(dòng)畫(huà),其中有兩個(gè)Fragment,布局都很簡(jiǎn)單,就不展示了。
動(dòng)畫(huà)代碼
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Before rotating, immediately set the alpha to 0. -->
<objectAnimator
android:valueFrom="1.0"
android:valueTo="0.0"
android:propertyName="alpha"
android:duration="0" />
<!-- Rotate. -->
<objectAnimator
android:valueFrom="180"
android:valueTo="0"
android:propertyName="rotationY"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:duration="@integer/card_flip_time_full" />
<!-- Half-way through the rotation (see startOffset), set the alpha to 1. -->
<objectAnimator
android:valueFrom="0.0"
android:valueTo="1.0"
android:propertyName="alpha"
android:startOffset="@integer/card_flip_time_half"
android:duration="@integer/card_flip_time_half" />
</set>
其他類似,分別表示左進(jìn)、左出、右進(jìn)、右出的動(dòng)畫(huà)。
Kotlin代碼
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_card_flip)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.add(R.id.container, CardFrontFragment())
.commit()
}
}
override fun onBackPressed() {
flipCard()
}
private var mShowingBack: Boolean = false
private fun flipCard() {
if (mShowingBack) {
supportFragmentManager.popBackStack()
mShowingBack = false
return
}
mShowingBack = true
supportFragmentManager.beginTransaction()
.setCustomAnimations(
R.animator.card_flip_right_in,
R.animator.card_flip_right_out,
R.animator.card_flip_left_in,
R.animator.card_flip_left_out
)
.replace(R.id.container, CardBackFragment())
.addToBackStack(null)
.commit()
}
重寫(xiě)了返回鍵,就是為了看效果。
去掉自定義的動(dòng)畫(huà),轉(zhuǎn)場(chǎng)如下圖所示:

是不是很突兀?看來(lái)有個(gè)動(dòng)畫(huà)還是真的不一樣的。
Circle Reveal動(dòng)畫(huà)
話不多說(shuō),先看效果:

ViewAnimationUtils.createCircularReveal()方法使我們可以有上述的效果。但是該類在API 21之上才有效果。
顯示代碼
顯示代碼如下:
private fun showView() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val cx = text.width / 2
val cy = text.height / 2
val finalRadius = Math.hypot(cx.toDouble(), cy.toDouble()).toFloat()
val anim = ViewAnimationUtils.createCircularReveal(text, cx, cy, 0f, finalRadius)
text.visibility = View.VISIBLE
anim.start()
} else {
text.visibility = View.VISIBLE
}
}
隱藏代碼
private fun hideView() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val cx = text.width / 2
val cy = text.height / 2
val initRadius = Math.hypot(cx.toDouble(), cy.toDouble()).toFloat()
val anim = ViewAnimationUtils.createCircularReveal(text, cx, cy, initRadius, 0f)
anim.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
super.onAnimationEnd(animation)
text.visibility = View.INVISIBLE
}
})
anim.start()
} else {
text.visibility = View.INVISIBLE
}
}
總結(jié)
動(dòng)畫(huà)確實(shí)很炫酷,不過(guò)要慎用,這周開(kāi)發(fā)就遇到了坑,有機(jī)會(huì)會(huì)以文章的形式記錄下來(lái)。
關(guān)于代碼,請(qǐng)見(jiàn) Github
參考: