Day25 - 加入简单的动画

今天想偷个懒,先为App加入一点动画,

主要是从欢迎页到登入页的过度动画。

Navigation transition

Navigation本身就有自带设定转场动画的方法enterAnimexitAnimpopEnterAnimpopExitAnim
能使用,这部份我就没多做设定了,使用的是Android提供的default值,实际跑起来就是简单的fade out/in。

app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim"

其他相关资讯可参考Navigate between fragments using animations

SharedElement transition

这边主要是加入在WelcomeFragmentLoginFragment的Logo。
首先在两个Fragment的对应ImageView设定transitionName:

<ImageView
    android:id="@+id/logo"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@mipmap/ic_launcher"
    android:transitionName="logo"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

接着在程序内使用Navigation跳转页面时加入Navigator.Extras

// ...
val extras = FragmentNavigator.Extras.Builder()
    .addSharedElement(binding.logo, "logo")
    .build()

NavHostFragment.findNavController(this@WelcomeFragment)
    .navigate(
        R.id.action_welcomeFragment_to_loginFragment,
        null,
        null,
        extras
    )
// ...

最後在LoginFragmentonCreate inflateTransition

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    sharedElementEnterTransition = TransitionInflater.from(context)
        .inflateTransition(R.transition.welcome_to_login)
}

使用的welcome_to_login.xml

<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="600"
    android:interpolator="@android:interpolator/accelerate_decelerate"
    android:transitionOrdering="together">
    <changeBounds />
    <changeTransform />
    <changeClipBounds />
    <changeImageTransform />
</transitionSet>

ObjectAnimator

LoginFragment的其他元件也加入Animator,看起来会比较顺畅。

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    binding.idLayout.postDelayed({
        enterAnimate(binding.idLayout)
    }, 200)
    binding.pwdLayout.postDelayed({
        enterAnimate(binding.pwdLayout)
    }, 250)
    binding.login.postDelayed({
        enterAnimate(binding.login)
    }, 300)
    
    // ...
}

private fun enterAnimate(v: View) {
    val alphaAnimator = ObjectAnimator.ofFloat(v, "alpha", 0.3f, 1f)
    val translationYAnimator =
        ObjectAnimator.ofFloat(v, "translationY", 250f.dpToPx(v.context).toFloat(), 0f)
    val animationSet = AnimatorSet()
    animationSet.interpolator = DecelerateInterpolator()
    animationSet.duration = 350L
    animationSet.playTogether(alphaAnimator, translationYAnimator)
    animationSet.start()
}

主要是利用不同的启动时间来造成一点时间差的效果。ObjectAnimator的教学已经有很多文章,这边就不多做说明了。

最後效果

https://i.imgur.com/J4PXaWT.gif


<<:  [Day25]DDL语句建立资料表2

>>:  Day 28:开始来学资料系结:使用目前所学,来个简单实作吧!(二)

Day21 NiFi - 与 GCP BigQuery 对接设定

今天要来介绍如何透过 NiFi 来与 GCP BigQuery 来做资料整合与操作。 What is...

Day 16: 物件导向设计、函数式设计 (待改进中... )

「什麽是物件导向? 对软件架构师来说: 物件导向是透过使用多型(Polymorphism) 来获得...

Day28 Policy-based authorization

之前有说到 ASP.NET Core Identity 使用的是基於 Claim 的验证,其实 AS...

[Angular] Day6. Sharing data between child and parent directives and components

我们了解到 Angular app 是由无数个大大小小的 Component 所组成的,所以就会常常...

Day 13 - Kotlin的集合(2)

Day 11 - Kotlin的函式(2) 昨天我们讲了list集合,以及如何取得数值,今天我们要继...