如何以编程方式更改导航图的起始目标[Jetpack]

问题描述 投票:20回答:2

基本上,我有以下导航图:

enter image description here

我想在到达它后立即将导航图中的起点改为fragment 2(为了防止在按下后退按钮时回到fragment 1 - 就像启动画面一样)。

这是我的代码:

navGraph = navController.getGraph();
navGraph.setStartDestination(R.id.fragment2);
navController.setGraph(navGraph);

但是,显然它不起作用,按下后退按钮后它会回到fragment 1

我做错了吗?还有其他解决方案吗?

android android-jetpack android-navigation android-architecture-navigation
2个回答
22
投票

更新:

如果您有这样的导航图:

<fragment
    android:id="@+id/firstFragment"
    android:name="com.appname.package.FirstFragment" >
    <action
        android:id="@+id/action_firstFragment_to_secondFragment"
        app:destination="@id/secondFragment" /> 
</fragment>

<fragment
    android:id="@+id/secondFragment"
    android:name="com.appname.package.SecondFragment"/>

并且您想要导航到第二个片段并使其成为图形的根,指定下一个NavOptions

NavOptions navOptions = new NavOptions.Builder()
        .setPopUpTo(R.id.firstFragment, true)
        .build();

并使用它们进行导航:

Navigation.findNavController(view).navigate(R.id.action_firstFragment_to_secondFragment, bundle, navOptions);

setPopUpTo(int destinationId, boolean inclusive) - 在导航之前弹出到指定的目的地。这将从后堆栈中弹出所有不匹配的目标,直到找到此目标。

destinationId - 弹出的目的地,清除所有干预目的地。

inclusive - 如果从后堆栈中弹出给定目标,则为true。

替代方案:

<fragment
    android:id="@+id/firstFragment"
    android:name="com.appname.package.FirstFragment" >
<action
    android:id="@+id/action_firstFragment_to_secondFragment"
    app:destination="@id/secondFragment"
    app:popUpTo="@+id/firstFragment"
    app:popUpToInclusive="true" /> 
</fragment>

<fragment
    android:id="@+id/secondFragment"
    android:name="com.appname.package.SecondFragment"/>

然后在你的代码上:

findNavController(fragment).navigate(
    FirstFragmentDirections.actionFirstFragmentToSecondFragment())

老答案

不推荐使用:clearTask中的操作和关联API的NavOptions属性已被弃用。

资料来源:https://developer.android.com/jetpack/docs/release-notes

如果你想将你的根片段更改为fragment 2(例如,在fragment 2上按回按钮后你将退出应用程序),你应该将下一个属性放到你的actiondestination

app:clearTask="true"

实际上它看起来是另一种方式:

<fragment
    android:id="@+id/firstFragment"
    android:name="com.appname.package.FirstFragment"
    android:label="fragment_first" >
    <action
        android:id="@+id/action_firstFragment_to_secondFragment"
        app:destination="@id/secondFragment"
        app:clearTask="true" /> 
</fragment>

<fragment
    android:id="@+id/secondFragment"
    android:name="com.appname.package.SecondFragment"
    android:label="fragment_second"/>

我已经添加了app:clearTask="true"来行动。

现在,当您执行从fragment 1fragment 2的导航时,请使用下一个代码:

Navigation.findNavController(view)
        .navigate(R.id.action_firstFragment_to_secondFragment);

-2
投票

我找到了解决方案,但它很难看。我想这可以用alpha库来预料,但我希望谷歌考虑简化/修复它,因为这是一个非常流行的导航模式。

阿列克谢的解决方案对我不起作用。我的问题是我使用以下方法在我的Actionbar上显示箭头:

NavigationUI.setupActionBarWithNavController(this, navController)

如果我按照Alexey的建议,我的新起始片段仍然有一个箭头指向我的初始起始片段。如果我按下向上箭头我的应用程序将重新启动,转换为自身(新的开始片段)

这是获得我想要的代码所需的代码:

  • 片段#1是我的应用程序最初启动的地方
  • 我可以在Fragment#1中进行Auth检查,然后以编程方式将start更改为片段#2。
  • 一旦进入片段#2,就没有向上箭头,按下后退按钮不会将你带到片段#1。

这是完成此任务的代码。在我的Activity's onCreate中:

// Setup the toolbar
val toolbar = findViewById<Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(false)

// Configure the navigation
val navHost = nav_host_fragment as NavHostFragment
graph = navHost.navController
        .navInflater.inflate(R.navigation.nav_graph)
graph.startDestination = R.id.welcomeFragment

// This seems to be a magical command. Not sure why it's needed :(
navHost.navController.graph = graph

NavigationUI.setupActionBarWithNavController(this, navHost.navController)

并且:

fun makeHomeStart(){
    graph.startDestination = R.id.homeFragment
}

然后在片段#1的onActivityCreated中,根据Alexey的建议:

override fun onActivityCreated(savedInstanceState: Bundle?) {
    ...

    // Check for user authentication
    if(sharedViewModel.isUserAuthenticated()) {

        (activity as MainActivity).makeHomeStart() //<---- THIS is the key
        val navOptions = NavOptions.Builder()
                .setPopUpTo(R.id.welcomeFragment, true)
                .build()
        navController.navigate(R.id.action_welcomeFragment_to_homeFragment,null,navOptions)

    } else {
        navController.navigate(R.id.action_welcomeFragment_to_loginFragment)
    }
}

关键代码是:(activity as MainActivity).makeHomeStart(),它只是在活动中运行一个方法来更改图形startDestination。我可以将其清理干净并将其转换为界面,但我会等待Google并希望他们改进整个过程。方法'setPopUpTo'似乎对我的命名很差,并且你命名从图中删除的片段并不直观。对我来说,他们在navOptions中进行这些更改也很奇怪。我认为navOptions只与他们所连接的导航动作有关。

我甚至不知道navHost.navController.graph = graph做了什么,但没有它,向上箭头返回。 :(

我正在使用Navigation 1.0.0-alpha06。

© www.soinside.com 2019 - 2024. All rights reserved.