【发布时间】:2018-04-02 05:13:01
【问题描述】:
你好堆栈溢出的优秀程序员!我已经为这个问题度过了愉快的一周,现在非常迫切需要解决方案。
场景
我使用的是 android.app.Fragment,不要与支持 Fragment 混淆。
我有 6 个子片段,名为:
FragmentOneFragmentTwoFragmentThreeFragmentAFragmentBFragmentC
我有 2 个名为的父片段:
FragmentNumericFragmentAlpha
我有 1 个活动名为:
MainActivity
它们的行为如下:
- 子片段是只显示视图的片段,它们不显示也不包含片段。
- 父片段用一个子片段填充其整个视图。他们能够用其他子片段替换子片段。
- 活动用父片段填充其大部分视图。它可以用其他父片段替换它。 因此,在任何时候,屏幕都只会显示一个子片段。
你可能已经猜到了,
FragmentNumeric 显示子片段 FragmentOne、FragmentTwo 和 FragmentThree。
FragmentAlpha 显示子片段 FragmentA、FragmentB 和 FragmentC。
问题
我正在尝试对父片段和子片段进行过渡/动画处理。子片段按预期平稳过渡。但是,当我过渡到新的父片段时,它看起来很糟糕。子片段看起来像是从其父片段运行独立的过渡。并且子片段看起来也从父片段中删除了。可以在这里查看它的 GIF https://imgur.com/kOAotvk。注意当我点击 Show Alpha 时会发生什么。
我能找到的最接近的问题和答案在这里:Nested fragments disappear during transition animation 但是所有的答案都是不令人满意的黑客攻击。
动画 XML 文件
我有以下动画效果(出于测试目的,持续时间较长):
fragment_enter.xml
<?xml version="1.0" encoding="utf-8"?>
<set>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="4000"
android:interpolator="@android:anim/linear_interpolator"
android:propertyName="xFraction"
android:valueFrom="1.0"
android:valueTo="0" />
</set>
fragment_exit.xml
<?xml version="1.0" encoding="utf-8"?>
<set>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="4000"
android:interpolator="@android:anim/linear_interpolator"
android:propertyName="xFraction"
android:valueFrom="0"
android:valueTo="-1.0" />
</set>
fragment_pop.xml
<?xml version="1.0" encoding="utf-8"?>
<set>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="4000"
android:interpolator="@android:anim/linear_interpolator"
android:propertyName="xFraction"
android:valueFrom="0"
android:valueTo="1.0" />
</set>
fragment_push.xml
<?xml version="1.0" encoding="utf-8"?>
<set>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="4000"
android:interpolator="@android:anim/linear_interpolator"
android:propertyName="xFraction"
android:valueFrom="-1.0"
android:valueTo="0" />
</set>
fragment_nothing.xml
<?xml version="1.0" encoding="utf-8"?>
<set>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="4000" />
</set>
MainActivity.kt
需要考虑的事项:第一个父片段 FragmentNumeric 没有进入效果,因此它始终为活动做好准备,并且没有退出效果,因为没有任何东西退出。我也在使用FragmentTransaction#add,而 FragmentAlpha 使用的是FragmentTransaction#replace
class MainActivity : AppCompatActivity {
fun showFragmentNumeric(){
this.fragmentManager.beginTransaction()
.setCustomAnimations(R.animator.fragment_nothing,
R.animator.fragment_nothing,
R.animator.fragment_push,
R.animator.fragment_pop)
.add(this.contentId, FragmentNumeric(), "FragmentNumeric")
.addToBackStack("FragmentNumeric")
.commit()
}
fun showFragmentAlpha(){
this.fragmentManager.beginTransaction()
.setCustomAnimations(R.animator.fragment_enter,
R.animator.fragment_exit,
R.animator.fragment_push,
R.animator.fragment_pop)
.replace(this.contentId, FragmentAlpha(), "FragmentAlpha")
.addToBackStack("FragmentAlpha")
.commit()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
showFragmentNumeric()
}
}
}
片段数字
在快速显示其第一个子片段方面与 Activity 执行相同的操作。
class FragmentNumeric : Fragment {
fun showFragmentOne(){
this.childFragmentManager.beginTransaction()
.setCustomAnimations(R.animator.fragment_nothing,
R.animator.fragment_nothing,
R.animator.fragment_push,
R.animator.fragment_pop)
.add(this.contentId, FragmentOne(), "FragmentOne")
.addToBackStack("FragmentOne")
.commit()
}
fun showFragmentTwo(){
this.childFragmentManager.beginTransaction()
.setCustomAnimations(R.animator.fragment_enter,
R.animator.fragment_exit,
R.animator.fragment_push,
R.animator.fragment_pop)
.replace(this.contentId, FragmentTwo(), "FragmentTwo")
.addToBackStack("FragmentTwo")
.commit()
}
fun showFragmentThree(){
this.childFragmentManager.beginTransaction()
.setCustomAnimations(R.animator.fragment_enter,
R.animator.fragment_exit,
R.animator.fragment_push,
R.animator.fragment_pop)
.replace(this.contentId, FragmentThree(), "FragmentThree")
.addToBackStack("FragmentThree")
.commit()
}
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if (savedInstanceState == null) {
if (this.childFragmentManager.backStackEntryCount <= 1) {
showFragmentOne()
}
}
}
}
其他片段
FragmentAlpha 遵循与 FragmentNumeric 相同的模式,分别用片段 A、B 和 C 替换片段一、二和三。
子片段只是显示以下 XML 视图并动态设置其文本和按钮单击侦听器以从父片段或活动调用函数。
view_child_example.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background"
android:clickable="true"
android:focusable="true"
android:orientation="vertical">
<TextView
android:id="@+id/view_child_example_header"
style="@style/Header"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/view_child_example_button"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
使用匕首和一些合同,我让子片段回调到它们的父片段并通过执行以下操作来托管活动:
FragmentOne 设置按钮点击监听器来做:
(parentFragment as FragmentNumeric).showFragmentTwo()
FragmentTwo 设置按钮点击监听器要做的事情:
(parentFragment as FragmentNumeric).showFragmentThree()
FragmentThree 不同,它会设置点击监听器来做:
(activity as MainActivity).showFragmentAlpha()
有人有解决这个问题的方法吗?
更新 1
我已按要求添加了一个示例项目:https://github.com/zafrani/NestedFragmentTransitions
它与我原始视频中的不同之处在于父片段不再使用具有 xFraction 属性的视图。所以看起来进入动画不再有那种重叠的效果了。然而,它仍然会从父片段中移除子片段并并排设置动画。动画完成后,片段三立即被片段A替换。
更新 2
父片段视图和子片段视图都使用 xFraction 属性。关键是在父动画时抑制子动画。
【问题讨论】:
-
问题已经非常清楚了,但是由于您似乎有一个干净的项目来显示该问题,因此如果您可以将其上传到某个地方会很酷。
-
请更新 Gif,好像没了。 UPD。对不起,我的错,找到了图片。
-
@natario 我添加了一个 github 链接。
标签: android android-fragments fragmenttransaction android-nested-fragment fragment-animation