4

NavigationComponent在我的应用程序上使用。

我有一个特定的流程,点击BottomSheetDialogFragment应用程序的按钮后应该导航到另一个片段。但是当那个 Fragment 被弹出时,我需要导航回上一个BottomSheetDialogFragment

由于某种原因,BottomSheetDialogFragment它被自动解雇。

Frag A : click on a button  
Frag A -> Dialog B : click on a button  
Frag A -> Dialog B -> Frag C : pop Frag C from the stack  
Frag A : Dialog B was automatically dismissed =;/  

如何防止这种解雇?


问:为什么我需要BottomSheetDialogFragment不被解雇?
A:我通过LiveData. 由于被解雇,BottomSheetDialogFragment它永远不会收到结果。

4

3 回答 3

4

这是不可能的。对话框目标实现了FloatingWindow 接口,该接口声明:

当您导航到新目的地时,实现此接口的目的地将自动从后台弹出。

因此,当您导航到目的地时,预计对话目的地会自动从后台堆栈中弹出<fragment>在多个对话目的地之间导航时不是这种情况(它们可以堆叠在一起)。

这个问题更多地解释了这里的限制,即:

  1. 对话框是始终位于活动窗口上方的单独窗口。这意味着无论底层的 FragmentManager 处于什么状态或者你做了什么 FragmentTransactions,对话框都会继续拦截系统返回按钮。

  2. 片段容器(即您的正常目的地)上的操作不会影响对话片段。如果您在嵌套的 FragmentManager 上执行 FragmentTransactions 也是如此。

因此,一旦您导航到<fragment>目的地,系统后退按钮实际工作的唯一方法是弹出所有浮动窗口(否则它们会先拦截后退按钮),因为这些窗口始终浮动在内容之上。

这不是导航组件强加的限制——同样的问题适用于BottomSheetDialogFragment有关 Fragment 返回堆栈和系统返回按钮的任何用法。

于 2021-04-23T21:42:46.280 回答
1

正如@ianhanniballake 所指出的,这是不可能的。

但这可以通过make fragment Cas aDailogFragment而不是 normal来实现Fragment,但这需要一些努力才能使其表现得像一个正常的片段。

在这种情况下,B&C都是对话框,因此它们将共享相同的后台堆栈。C因此,当从to弹出返回堆栈时B,您仍然会看到 BottomSheetDialgFragmentB显示。

C要修复使用以下主题的有限窗口:

<style name="DialogTheme" parent="Theme.MyApp">
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowFullscreen">false</item>
    <item name="android:windowIsFloating">false</item>
</style>

Theme.MyApp您的应用程序的主题在哪里。

C然后通过覆盖将其应用于getTheme()

class FragmentC : DialogFragment() {

    //.....

    override fun getTheme(): Int = R.style.DialogTheme
    
}

您还需要C将导航图从 a更改fragment为 a dialog

<dialog
        android:id="@+id/fragmentC"
        android:name="....">
</dialog>

预览:

于 2021-08-02T21:39:57.397 回答
0

您不希望关闭对话框,因为它会停留在下一个目的地之上。

“听结果”,如果你的意思是findNavController().currentBackStackEntry.savedStateHandle.getLiveData(MY_KEY)

那么您应该能够将结果设置previousBackStackEntry为,因为它将在您的对话之前为您提供目的地。

Frag A : click on a button 
Frag A -> Dialog B : click on a button (automatically popped-off)
Frag A -> Dialog B -> Frag C : pop Frag C from the stack
  

然后

class FragA : Fragment() {
    
    ...

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

        findNavController().currentBackStackEntry.savedStateHandle?.getLiveData<MyResult>(MY_KEY).observe(viewLifecycleOwner) {
           // get your result here
           // show Dialog B again if you like ?
        }
    }
}

class FragC : Fragment() {

    ...

    private fun setResultAndFinish(result: MyResult) {
        findNavController().apply { 
            previousBackStackEntry?.savedStateHandle?.set(MY_KEY, result)
            popBackStack()
        }
    }
    
}
于 2021-04-24T03:01:49.097 回答