android_基础_跳转动画使用容器转换

容器转换

前沿:从一个新闻列表跳转到新闻详情页, 跳转的动画使用容器转换,如MainActivity下的RestFragment内部的嵌套的TabFragment跳转到NewsDetailFragment

基本实现

TabRestFragment.kt

//跳转监听
//listitem 点击跳转到新闻详情界面,跳转参数为列表item的数据
    override fun rvItemOnclick(viewRoot: View, news: Data?) {
        if(news != null){
            exitTransition = MaterialElevationScale(false).apply {
                duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
            }
            reenterTransition = MaterialElevationScale(true).apply {
                duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
            }
            val newsCardDetailTransitionName = getString(R.string.news_card_detail_transition_name)
            val extras = FragmentNavigatorExtras(viewRoot to  newsCardDetailTransitionName)
            val actionRestFragmentToNewsDetailFragment: NavDirections =
                RestFragmentDirections.actionRestFragmentToNewsDetailFragment(news)
            this.findNavController().navigate(actionRestFragmentToNewsDetailFragment, extras)
        }
    }

NewsDetailFragment.kt

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        sharedElementEnterTransition = MaterialContainerTransform().apply {
            drawingViewId = R.id.nav_main_host_fragment
            duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
            scrimColor = Color.TRANSPARENT
            setAllContainerColors(requireContext().themeColor(R.attr.colorSurface))
        }
    }

这里的themeColor来自Context拓展工具类

ContextExtensions.kt

package com.example.module_main.utils

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.util.TypedValue
import android.view.animation.AnimationUtils
import android.view.animation.Interpolator
import androidx.annotation.AttrRes
import androidx.annotation.ColorInt
import androidx.annotation.DrawableRes
import androidx.annotation.StyleRes
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.res.use

/**
 * Retrieve a color from the current [android.content.res.Resources.Theme].
 */
@ColorInt
@SuppressLint("Recycle")
fun Context.themeColor(
    @AttrRes themeAttrId: Int
): Int {
    return obtainStyledAttributes(
        intArrayOf(themeAttrId)
    ).use {
        it.getColor(0, Color.MAGENTA)
    }
}

此时已经实现了从列表到详情页的扩展动画,但是此时返回时候切没有详情到列表的折叠动画

原因:

Typically, this first issue of the collapse not working is because when the Android Transition system is trying to run your return transition, the list of emails hasn’t been inflated and populated into the RecyclerView yet. We need a way to wait until our HomeFragment lays out our list before we start our transitions.
The Android Transition system provides methods to do just that - postponeEnterTransition and startPostponedEnterTransition. If postponeEnterTransition is called, any entering transition to be run will be held until a closing call to startPostponedEnterTransition is called. This gives us the opportunity to “schedule” our transitions until after the RecyclerView has been populated with emails and the transition is able to find the mappings you configured.

解决方案: (注意到根碎片也就是MainActivity下的RestFragment,而不是TabRestFragment)下添加两行代码

// 尝试运行您的返回转换时,电子邮件列表尚未膨胀并填充到其中RecyclerView。HomeFragment在开始转换之前,我们需要一种方法来等待我们列出我们的列表。
// 如果postponeEnterTransition被调用,任何要运行的进入转换将被保持,直到调用结束调用startPostponedEnterTransition。这使我们有机会“安排”我们的转换,直到RecyclerView用电子邮件填充并且转换能够找到您配置的映射之后。
postponeEnterTransition()
view.doOnPreDraw { startPostponedEnterTransition() }

优化

问题一

从列表跳转到详情页的展开动画进行的时候,跳转列表的其他列表消失不见显示白色

电子邮件列表消失的问题是因为当使用导航组件导航到一个新的 Fragment 时,当前的 Fragment 会立即被删除并替换为我们新传入的 Fragment。为了在被替换后仍保持电子邮件列表可见,您可以将退出转换添加到HomeFragment.

MDC-Android 提供了两种转换来为您执行此操作 -Hold和MaterialElevationScale. 该Hold过渡只是保持其目标在当前位置,同时MaterialElevationScale运行的微妙尺度动画。

注意在根布局设置

RestFragmenet.kt

 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // 尝试运行您的返回转换时,电子邮件列表尚未膨胀并填充到其中RecyclerView。HomeFragment在开始转换之前,我们需要一种方法来等待我们列出我们的列表。
        // 如果postponeEnterTransition被调用,任何要运行的进入转换将被保持,直到调用结束调用startPostponedEnterTransition。这使我们有机会“安排”我们的转换,直到RecyclerView用电子邮件填充并且转换能够找到您配置的映射之后。
        postponeEnterTransition()
        view.doOnPreDraw { startPostponedEnterTransition() }
        
        
        //设置进出动画,避免列表跳转到详情页除了该列表其他部分白屏的情况
        exitTransition = MaterialElevationScale(false).apply {
            duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
        }
        reenterTransition = MaterialElevationScale(true).apply {
            duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
        }
		//...

}

接下来,为了确保将MaterialElevationScale过渡作为一个整体应用于主屏幕,而不是应用于层次结构中的每个单独视图,将RecyclerViewin标记fragment_tab_in_rest_rest.xml为过渡组。

	<androidx.recyclerview.widget.RecyclerView

            android:transitionGroup="true"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
            android:id="@+id/rv_tap_rest_overview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:bind_listData="@{viewModel.news}"

            tools:listitem="@layout/listitem_tabs_viewholder1"
            tools:itemCount="2"/>
上一篇:go duration比较


下一篇:Vue 页面如何监听用户预览时间