Fen*_*der 4 android android-animation kotlin android-transitions android-jetpack
我正在尝试使用片段之间共享元素的简单动画进行过渡。在第一个片段中,我在 RecyclerView 中有元素,在第二个片段中 - 完全相同的元素(在单独的 xml 布局中定义,在列表中的元素也是这种类型)在顶部和视图的其余部分中的细节。我正在为 bindViewHolder 和目标片段的 onCreateView 中的所有元素提供各种 transitionNames 我正在阅读它们并将它们设置为我想要进行过渡的元素。无论如何动画没有发生,我没有任何其他想法。下面我将我的代码片段来自源和目标片段以及列表适配器:
列表适配器:
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = list[position]
ViewCompat.setTransitionName(holder.view, item.id)
holder.view.setOnClickListener {
listener?.onItemSelected(item, holder.view)
}
...
}
interface interactionListener {
fun onItemSelected(item: ItemData, view: View)
}
Run Code Online (Sandbox Code Playgroud)
列表片段(来源):
override fun onItemSelected(item: ItemData, view: View) {
val action = ListFragmentDirections.itemDetailAction(item.id)
val extras = FragmentNavigatorExtras(view to view.transitionName)
val data = Bundle()
data.putString("itemId", item.id)
findNavController().navigate(action.actionId, data, null, extras)
}
Run Code Online (Sandbox Code Playgroud)
源片段布局:
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/pullToRefresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/item_overview_row" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
Run Code Online (Sandbox Code Playgroud)
DetailFragment(目标):
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val rootView = inflater.inflate(R.layout.fragment_detail, container, false)
val itemId = ItemDetailFragmentArgs.fromBundle(arguments).itemId
(rootView.findViewById(R.id.includeDetails) as View).transitionName = itemId
sharedElementEnterTransition = ChangeBounds().apply {
duration = 750
}
sharedElementReturnTransition= ChangeBounds().apply {
duration = 750
}
return rootView
}
Run Code Online (Sandbox Code Playgroud)
细节片段布局:
<include
android:id="@+id/includeDetails"
layout="@layout/item_overview_row"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Run Code Online (Sandbox Code Playgroud)
ItemOverviewRowLayout(这个在 recyclerView 中作为项目包含在目标片段中作为标题):
<androidx.cardview.widget.CardView 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="wrap_content"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
android:orientation="vertical" >
Run Code Online (Sandbox Code Playgroud)
我还使用 Jetpack 导航、共享元素和相同 layout.xml 描述的元素制作了另一个应用程序,并且它正在工作,因为我没有从 recyclerView 过渡到目标片段。也许我在这里错了,将 transitionName 设置为目标片段中的 found 视图?我不知道如何另辟蹊径,因为目标包含布局的 ID 应该是唯一的,因为 recyclerView 项目。
好的,我发现使用共享元素输入动画应该是什么样子:在 DetailFragment (Target) 中,您应该在 onViewCreated启动时运行延迟EnterTransition( )(我从 onCreateView 中的代码可以移动到 onViewCreated)。现在您有时间使用 transitionName 签署目标视图元素。在加载数据和查看结束后,您必须运行startPostponedEnterTransition()。不做的话ui会卡死,所以不能在delayEnterTransition和startPostponedEnterTransition之间做耗时的操作。
无论如何,现在的问题是返回转换。因为当然这是相同的情况 - 您必须在发布动画之前重新加载 recyclerView 。当然你也可以使用welcomeEnterTransition(即使是返回转换)。就我而言,我有由 LiveData 包装的列表。在源片段生命周期观察者正在检查数据。还有另一个挑战 - 如何确定是否加载了数据。理论上,使用 recyclerView 您可以使用有用的内联函数:
inline fun <T : View> T.afterMeasure(crossinline f: T.() -> Unit) {
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
if (measuredWidth > 0 && measuredHeight > 0) {
viewTreeObserver.removeOnGlobalLayoutListener(this)
f()
}
}
})
Run Code Online (Sandbox Code Playgroud)
}
...在应用布局管理器和适配器的代码中,您可以像这样使用它:
recyclerView.afterMeasure { startPostponedEnterTransition() }
Run Code Online (Sandbox Code Playgroud)
它应该确定返回动画应该开始的时间(您必须确定 recyclerView 项目中的 transitionNames 是否正确,以便过渡可以具有目标视图项目)
| 归档时间: |
|
| 查看次数: |
3712 次 |
| 最近记录: |