web-dev-qa-db-ja.com

ナビゲーショングラフの開始先をプログラムで変更する方法[Jetpack]

基本的に、次のナビゲーショングラフがあります。

enter image description here

スプラッシュ画面のように、戻るボタンを押したときにfragment 2に戻らないようにするために、ナビゲーショングラフの開始点をfragment 1に到達した直後に変更したい。

これは私のコードです:

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

しかし、明らかにそれは機能しておらず、戻るボタンを押すとfragment 1に戻ります。

私は間違っていますか?他の解決策はありますか?

28
Shynline

UPDATE:

このようなナビゲーショングラフがある場合:

<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"/>

そして、2番目のフラグメントに移動してグラフのルートにし、次の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属性およびNavOptionsの関連APIは廃止されました。

ソース: https://developer.Android.com/jetpack/docs/release-notes


ルートフラグメントをfragment 2に変更する場合(たとえば、fragment 2の戻るボタンを押した後、アプリを終了します)、次の属性をactionまたはdestination

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 1からfragment 2へのナビゲーションを実行するとき、次のコードを使用します。

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

私はこれに対する解決策を見つけましたが、それはいです。これはアルファライブラリで期待されていることだと思いますが、これは非常に人気のあるナビゲーションパターンであるため、Googleがこれを簡素化/修正することを検討することを望みます。

Alexeyのソリューションは私にはうまくいきませんでした。私の問題は、使用して上矢印がアクションバーに表示されることでした:

NavigationUI.setupActionBarWithNavController(this, navController)

アレクセイが上記のように提案したように、新しい開始フラグメントには、まだ最初の開始フラグメントを指す矢印がありました。上矢印を押すと、アプリは再起動し、それ自体に移行します(新しい開始フラグメント)

私が望んでいたものに到達するために必要なコードは次のとおりです:

  • フラグメント#1は、アプリケーションが最初に起動する場所です
  • フラグメント#1で認証チェックを行い、プログラムでフラグメント#2の開始を変更できます。
  • フラグメント#2に入ると上矢印は表示されず、戻るボタンを押してもフラグメント#1に移動しません。

これを実現するコードを次に示します。私のアクティビティの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
}

次に、Alexeyの提案によるフラグメント#1のonActivityCreatedで:

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を使用しています。

1
szaske