我有FragmentA、FragmentB和DialogFragment(BottomDialogFragment)。我将它们缩写为A、B和D
点击A中的按钮后会显示D,表示A -〉D
点击D中的按钮后,显示B,表示D -〉B
我在navigation.xml中配置它们
<fragment
android:id="@+id/A"
android:name="com.example.A">
<action
android:id="@+id/A_D"
app:destination="@id/D" />
</fragment>
<dialog
android:id="@+id/D"
android:name="com.example.D">
<action
android:id="@+id/D_B"
app:destination="@id/B" />
</dialog>
<fragment
android:id="@+id/B"
android:name="com.example.B">
</fragment>
现在,当我单击A中的按钮时,片段将跳转到D。
然后我点击D中的按钮,片段将跳转到B。
但是当我弹出B中的导航堆栈时,它将返回到A,并且D不显示。
我该怎么办?我希望D还存在于A的表面。
4条答案
按热度按时间wa7juj8i1#
我该怎么办?我希望D仍然存在于A的表面上。
到目前为止,这是不可能的,因为对话框是在与活动/片段不同的窗口中处理的;这是因为
Dialog
实现了FloatingWindow interface。检查this answer以了解更多说明。
但要回答你的问题,有两种方法:
1.**方法一:**将片段
B
更改为DailogFragment
,在这种情况下,B
和D
都是对话框,因此当您弹出堆栈从B
返回到D
时,您仍然会看到D
显示。1.**方法2:**设置一个标志,如果从
B
返回到D
,则重新显示D
。实际上,方法2并不是很好,因为当您从
D
转到B
时,它不会将D
保留在后台堆栈中;这只是一个变通办法;此外,当对话框从B
返回到D
时,用户将看到对话框转换/淡入淡出动画;所以这一点也不自然。所以,这里只讨论方法1。方法一详细:
优点:
缺点:
DialogFragment B
具有比正常片段/活动有限的窗口。B
不再是一个普通的片段,而是一个DialogFragment
,因此您可能会遇到一些其他的限制。要解决
B
的有限窗口,您可以使用以下主题:其中
Theme.MyApp
是应用的主题。然后使用
getTheme()
将其应用于B
:你还需要将导航图中的
B
更改为对话框:预览:
iibxawm42#
请参考link以获得完整的工作示例。
您需要利用NavigationUI全局操作(如here所述),以便能够导航“back”到目的地。将以下代码放入main_graph xml中:
接下来,在你的活动中添加这些以捕获回按:
这就像delegatesin swift
接下来在FragmentB中,添加以下内容:
然后您可以根据需要导航回DialogFragment,这种方式不使用popBackStack,因为您的 use case 是一个自定义行为,不是NavigationUI框架处理的(您需要实现它)。
ohfgkhjo3#
不需要使用controller.popBack()弹出堆栈,因为堆栈是由导航库管理的。请注意,堆栈基于LIFO操作,因此这就是为什么片段消失的原因。
您需要添加更多导航图操作:
然后,在“片段”对话框中添加以下内容:
对于OK/Yes:--
取消/编号:--
最后,在B片段中,覆盖back按钮并执行以下操作:
hkmswyz64#
这里是解决这个问题的另一个方法。像大多数方法一样,这个方法也有一些缺点。我在下面的“缺点”一节中概述了缺点。
理论
解决方案涉及一些“较旧”的Android机制,即早于导航控制器的机制(我们并不总是有导航控制器)。解决方案围绕以下几个事实:
1.所有的片段都存在于一些
FragmentManager
中。导航控制器并不神奇,它仍然在幕后使用FragmentManager
。事实上,你可以把导航控制器看作是FragmentManager
的 Package 器。1.所有的fragment都有它自己的小
FragmentManager
。你可以通过fragment中的childFragmentManager
访问它。在childFragmentManager
上启动的任何fragment都被认为是该fragment的孩子。1.当一个片段被移动到“backstack”时,它的所有子元素都会随之移动。
1.当一个片段被恢复时,它的子片段也被恢复。
有了这四个事实,我们可以制定一个解决方案。
我们的想法是,如果我们在一个片段的
childFragmentManager
上显示所有DialogFragment
,那么我们就可以保持导航到其他片段的能力,而不会出现任何对话框相关的问题。这是因为当我们从FragA导航到FragC时,FragA的所有孩子都被移动到后台堆栈。由于我们使用childFragmentManager
启动了DialogFragment
,DialogFragment
也会被自动忽略。现在,当用户移回我们的片段(FragA)时,我们的
DialogFragment
再次显示,因为FragA的childFragmentManager
也被恢复了。我们的DialogFragment
位于childFragmentManager
中。实现
现在我们知道了如何解决这个问题,让我们开始实现它。
为了简单起见,我们假设我们有片段
FragA
和FragC
以及对话框DialogB
。第一件事是,尽管Navigation组件很好,但如果我们想这样做,我们不能使用它来启动对话框。如果你使用安全参数,你可以继续获得它的好处,因为技术上安全的参数并没有绑定到Navigation组件。下面是一个启动对话框B的例子:
现在我们可以让
DialogB
启动FragC
,但有一个问题。因为我们使用的是childFragmentManager
,所以导航控制器实际上看不到DialogB
。这意味着对于导航控制器来说,我们正在从FragA
启动FragC
。如果在导航图中有多个到DialogB
的边,这可能会产生问题。解决这个问题的方法是将DialogB
的所有方向都设置为全局。这是这个解决方法的最终缺点。在这种情况下,我们可以声明一个全局操作给FragC
,并通过缺点
因此,这种方法有一些明显的缺点。最大的缺点是对话框可以导航到的所有片段都应该声明为全局操作。唯一的异常值是对话框是否只有一条边。如果对话框只有一条边,并且不太可能添加新的边,那么从技术上讲,您可以将操作添加到它唯一的父片段中。
例如,如果
DialogC
可以启动FragmentC
和FragmentD
,并且DialogC
可以从FragmentA
和FragmentZ
(2个边)启动,则DialogC
必须使用全局操作来启动FragmentC
或FragmentD
。另一个缺点是我们不能再使用导航控制器来启动需要启动其他非对话框片段的对话框片段。这个缺点是温和的,因为我们至少仍然可以使用安全参数。