本篇学习笔记彻底根据官方文档中使用动画显示或隐藏视图部分学习的,基本是照着文档学习的,点击连接能够直接跳转到官方文档部分。android
有时候,咱们须要在屏幕上显示新的信息,同时移除旧的信息,通常状况下咱们经过VISIBILITY
或者GONE
来对须要显示或者隐藏的视图进行设置,这样作的坏处是显示或者隐藏的动做变化很是突兀,并且有时候变化很快致使用户没法注意到这些变化。这时就可使用动画显示或者隐藏视图,一般状况下使用圆形揭露动画,淡入淡出动画或者卡片反转动画。markdown
经过这篇笔记的学习,能够学习到以下内容:app
经过控制视图的alpha
建立淡入淡出的动画
同时也会学习到使用ViewPropertyAnimator
控制动画。ide
建立卡片翻转动画
同时也会学习到设置Fragment
切换时的动画。oop
建立圆形揭露动画
同时也会学习到ViewAnimationUtils
类中提供的createCircularReveal
方法的使用。布局
淡入淡出动画会逐渐淡出一个View
或者ViewGroup
,同时淡入另外一个。此动画适合在应用中切换内容或者视图的状况。这里使用ViewPropertyAnimator
来建立这种动画。学习
下面的动画是从进度指示器切换到某些内容文字的淡入淡出示例。动画
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--淡入淡出动画-->
<Button
android:id="@+id/btn_use_fade_in_fade_out_animator"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"
android:onClick="doClick"
android:text="@string/use_fade_in_fade_out_animator"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="w,1:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_use_fade_in_fade_out_animator">
<TextView
android:id="@+id/tv_content"
android:layout_width="0dp"
android:layout_height="0dp"
android:padding="16dp"
android:text="@string/test_use_fade_in_fade_out_animator_text"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!--进度条-->
<ProgressBar
android:id="@+id/loading_progress"
style="?android:progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
复制代码
设置淡入淡出动画:ui
GONE
,这一点在布局文件中已经设置。View
的时候,首先将其alpha
设置为0,这样能够保证View
已经显示可是不可见。View
的alpha
属性从0变化到1,淡出的动画将其所在的View
的alpha
属性从1变化到0GONE
,从而加快处理速度。实现以下:google
//开始执行淡入淡出动画
private fun crossFade() {
//设置须要淡入的View的alpha为0,可见性为VISIBLE
mBinding.tvContent.apply {
alpha = 0f
visibility = View.VISIBLE
//经过动画将透明度变为1.0
animate()
.alpha(1.0f)
.setDuration(mShortAnimationDuration.toLong())
.start()
}
//设置须要淡出的动画,将其alpha从1变为0,并经过监听动画执行事件,在动画结束后将View的可见性设置为GONE
mBinding.loadingProgress.animate()
.alpha(0f)
.setDuration(mShortAnimationDuration.toLong())
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
super.onAnimationEnd(animation)
mBinding.loadingProgress.visibility = View.GONE
}
})
.start()
}
复制代码
最终执行的效果以下:
卡片翻转经过显示模拟卡片翻转的动画,在内容视图之间添加动画,这里经过设置Fragment
切换的动画来演示翻转动画的使用。
在这里共须要四个动画,其中两个用于卡片正面向左淡出以及从左侧淡入的动画,另外两个则用于从右侧淡入以及从右侧淡出的动画,动画文件以下:
card_flip_left_in.xml
<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="1" />
</set>
复制代码
card_flip_left_out.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Rotate. -->
<objectAnimator
android:valueFrom="0"
android:valueTo="180"
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 0. -->
<objectAnimator
android:valueFrom="1.0"
android:valueTo="0.0"
android:propertyName="alpha"
android:startOffset="@integer/card_flip_time_half"
android:duration="1" />
</set>
复制代码
card_flip_right_in.xml
<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="1" />
</set>
复制代码
card_flip_right_out.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Rotate. -->
<objectAnimator
android:valueFrom="0"
android:valueTo="-180"
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 0. -->
<objectAnimator
android:valueFrom="1.0"
android:valueTo="0.0"
android:propertyName="alpha"
android:startOffset="@integer/card_flip_time_half"
android:duration="1" />
</set>
复制代码
上面的动画文件时直接复制的文档中的文件内容,能够在官方文档中直接看到。
建立好了动画文件,还须要建立两个Fragment
的布局文件,分别对应正面的Fragment
和背面的Fragment
,下面是正面Fragment
的布局文件:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="#a6c">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:text="@string/card_front"
android:textSize="20sp"
android:textColor="#fff"
android:textStyle="bold"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
复制代码
背面的Fragment
则只显示一张图片:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:contentDescription="@null"
android:src="@mipmap/ic_default_mine_banner"
android:scaleType="centerCrop"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
复制代码
而后就能够建立Fragment
而后使用了:
//卡片切换的Fragment
class CardFrontFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_card_front, container, false)
}
}
class CardBackFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_card_back, container, false)
}
}
复制代码
在Activity
中,当切换Fragment
的时候,经过向事务中设置自定义动画资源来设置Fragment
切换时的动画:
//显示卡片背面
private fun showCardBack() {
if (mShowingBack) {
//supportFragmentManager.popBackStack()
return
}
mShowingBack = true
supportFragmentManager.beginTransaction().apply {
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.fl_content, mBackFragment)
//addToBackStack(null)
commit()
}
}
//显示卡片正面
private fun showCardFront(){
if(!mShowingBack){
//supportFragmentManager.popBackStack()
return
}
mShowingBack = false
supportFragmentManager.beginTransaction().apply {
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.fl_content, mFrontFragment)
//addToBackStack(null)
commit()
}
}
复制代码
这里的切换方式和文档里面的略有不一样,可是没有太大区别。
以后运行上面的代码就能够看到Fragment
在切换时的动画了:
当须要显示或者隐藏一组界面元素时,可使用圆形揭露动画。ViewAnimationUtils.createCircleReveal()
方法能够建立圆形揭露动画,此动画在ViewAnimationUtils
类中提供,适用于5.0及更高版本。
下面的代码演示了经过圆形揭露动画显示以前不可见的视图:
首先建立须要显示和隐藏的布局:
<Button
android:id="@+id/btn_show_view_with_circle_animator"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/fl_content"
app:layout_constraintLeft_toLeftOf="parent"
android:text="@string/show_view_with_circle_animator"
app:layout_constraintRight_toLeftOf="@id/btn_hide_view_with_circle_animator"
android:layout_marginStart="10dp"
android:onClick="doClick"
/>
<Button
android:id="@+id/btn_hide_view_with_circle_animator"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBaseline_toBaselineOf="@id/btn_show_view_with_circle_animator"
app:layout_constraintLeft_toRightOf="@id/btn_show_view_with_circle_animator"
app:layout_constraintRight_toRightOf="parent"
android:text="@string/hide_view_with_circle_animator"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:onClick="doClick"
/>
<TextView
android:id="@+id/tv_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@id/btn_show_view_with_circle_animator"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintDimensionRatio="w,1:1"
android:background="@color/color_f54949"
android:layout_margin="10dp"
/>
复制代码
下面是经过圆形揭露动画隐藏最下面的TextView
:
//使用圆形揭露动画隐藏视图
private fun hideViewWithCircleAnimator() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val cx = mBinding.tvView.width / 2
val cy = mBinding.tvView.height / 2
val anim =
ViewAnimationUtils.createCircularReveal(mBinding.tvView, cx, cy, cx.toFloat(), 0f)
anim.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
super.onAnimationEnd(animation)
//动画运行结束后将View设置为GONE
mBinding.tvView.visibility = View.GONE
}
})
anim.start()
} else {
mBinding.tvView.visibility = View.GONE
}
}
复制代码
下面的代码演示使用圆形揭露动画显示最下面的TextView
:
//使用圆形揭露动画显示视图
private fun showViewWithCircleAnimator() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val cx = mBinding.tvView.width / 2
val cy = mBinding.tvView.height / 2
val anim =
ViewAnimationUtils.createCircularReveal(mBinding.tvView, cx, cy, 0f, cx.toFloat())
mBinding.tvView.visibility = View.VISIBLE
anim.start()
} else {
mBinding.tvView.visibility = View.VISIBLE
}
}
复制代码
运行效果以下:
实现上面的圆形揭露动画主要就是依赖于ViewAnimationUtils
类中提供的createCircularReveal
方法,这个方法接收5个参数分别是:
经过布局文件能够看到,上面我要对tv_view
实现圆形揭露动画,这个View
的长宽时相等的,因此我这边设置的中心点坐标就是宽度和高度的一半,同时在隐藏的时候,设置的起始半径就是宽度的一半,结束半径就是0