Androidナビゲーションアーキテクチャコンポーネント-現在表示されているフラグメントを取得します


103

ナビゲーションコンポーネントを試す前は、フラグメントトランザクションを手動で実行し、現在のフラグメントをフェッチするためにフラグメントタグを使用していました。

val fragment:MyFragment = supportFragmentManager.findFragmentByTag(tag):MyFragment

現在、メインのアクティビティレイアウトには、次のようなものがあります。

<fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/nav_host"
        app:navGraph= "@navigation/nav_item"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:defaultNavHost= "true"
        />

ナビゲーションコンポーネントで現在表示されているフラグメントを取得するにはどうすればよいですか?やってる

supportFragmentManager.findFragmentById(R.id.nav_host)

を返しNavHostFragment、表示された「MyFragment」を取得したいと思います。

ありがとうございました。


4
現在のフラグメントを取得する方法はありませんstackoverflow.com/a/50689587/1268507 何を達成しようとしていますか?多分それのためのいくつかの他の解決策があります。
アレックス

フラグメントからカメラインテントを開始し、写真を撮り、撮影した画像を使用する必要がありました。そうするために、私は活動を開始し、onActivityResult私の主な活動の結果を待ちました。フラグメントを取得できなかったので、これらすべてをフラグメント自体に移動しただけで、機能しているようです。
アリン

そのフラグメントオブジェクトに対して操作を実行しますか?または、どのフラグメントを表示したいですか?
ランジャン2018

回答:


106

私は今のところ方法を見つけることができました、そしてそれは次の通りです:

NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host);
navHostFragment.getChildFragmentManager().getFragments().get(0);

もちろん、あなたはそれが最初の断片であることを知っています。私はまだこれなしで方法を調査しています。私はそれが最善の方法ではないことに同意しますが、それは今のところ何かであるはずです。


7
実用的な解決策を見るのは素晴らしいことです。私はこれをあきらめて、アクティビティとフラグメントの間で共有viewModelを使い始めました。これは、コールバックや直接アクセスを必要とせずに、それらの間でイベントを渡すことができることを意味します。
アリン

1
このバグレポートの問題issuetracker.google.com/issues/119800853に記載されているように、これは正しい方法ではありません。正解の変更をご検討ください!
ニコラスピエトリ

2
前述のように、これは解決策ではなく、適切な解決策が見つかるまでの回避策です。
AndreiToader19年

1
これはうまくいきます、どうもありがとう。バグトラッカーで提案されているようにgetPrimaryNavigationFragment()を試しましたが、うまくいきません。
ジェリーフー

1
このソリューションに基づいて、現在のフラグメントが(idではなく)特定のタイプであるかどうかを確認できるkotlin関数を作成しましたnavHostFragment!!.childFragmentManager.fragments.any { it.javaClass == fragmentClass && it.isVisible }。非常によく似ています。それが誰にでも役立つことを願っています!
PKuijpers20年

50

現在のフラグメントインスタンスを取得する方法はありません。ただし、以下のコードを使用して、最後に追加されたフラグメントのIDを取得できます。

navController.currentDestination?.getId()

ナビゲーションファイルでIDを返します。お役に立てれば。


ご回答ありがとうございます。フラグメントを操作できるように、フラグメントを取得する必要がありました。navControllerはそれを返すことができないので、共有ビューモデルを使用してアクティビティとそのフラグメントの間で会話することを終了しました
Alin 2018

8
返されたIDがnavxmlのIDと一致すると予想しましたが、一致しません。つまり、navController.getCurrentDestination()。getId()== R.id.myfrag
LeresAldtai19年

4
@LeresAldtaiナビゲーションファイル内のフラグメントのIDと一致します。
slhddn

1
@slhddnありがとうございます。あなたのコメントは私を助け、フラグメントからIDを取得し、これを機能させることができました。他の誰かに役立つ場合に備えて、ここに私のコードで答えを追加しました。乾杯。
FrancislainyCampos20年

36

navフラグメントのchildFragmentManagerprimaryNavigationFragmentプロパティを確認する必要があります。これは、現在表示されているフラグメントが参照される場所です。

val navHost = supportFragmentManager.findFragmentById(R.id.main_nav_fragment)
    navHost?.let { navFragment ->
        navFragment.childFragmentManager.primaryNavigationFragment?.let {fragment->
                //DO YOUR STUFF
        }
    }
}

3
この方法は、現在fragmentManagerに記載されて issuetracker.google.com/issues/119800853
ニコラスPietri氏

これは少し問題のようです。私はonSupportNaigateUp()への呼び出しを取得するためのナビゲーションをアクションバーを設定する必要がアップ取り扱い
filthy_wizard

20

これは最もクリーンなソリューションのようです。更新:拡張機能をプロパティに変更しました。IgorWojdaに感謝します。

1.次の拡張機能を作成します

import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager

val FragmentManager.currentNavigationFragment: Fragment?
    get() = primaryNavigationFragment?.childFragmentManager?.fragments?.first()

2.次のように使用ActivityNavHostFragmentます。

val currentFragment = supportFragmentManager.currentNavigationFragment

2
ニース-これを変更します-拡張機能をFragmentManager.currentNavigationFragment(関数としてではなく)プロパティとして定義します
IgorWojda20年

17

addOnDestinationChangedListener持っている活動で使用NavHostFragment

Javaの場合

 NavController navController= Navigation.findNavController(MainActivity.this,R.id.your_nav_host);

        navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
            @Override
            public void onDestinationChanged(@NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments) {
                Log.e(TAG, "onDestinationChanged: "+destination.getLabel());
            }
        });

Kotlinの場合

var navController :NavController=Navigation.findNavController(this, R.id.nav_host_fragment)
    navController.addOnDestinationChangedListener { controller, destination, arguments ->
        Log.e(TAG, "onDestinationChanged: "+destination.label);

    }

9

これは遅いかもしれませんが、まだ探している人にとっては

val currentFragment = NavHostFragment.findNavController(nav_host_fragment).currentDestination?.id

その後、あなたは次のようなことをすることができます

if(currentFragment == R.id.myFragment){
     //do something
}

これはkotlin用であり、Javaコードはほぼ同じである必要があることに注意してください



5
navController().currentDestination?.id

あなたの現在FragmentのIDをどこに与えるでしょう

private fun navController() = Navigation.findNavController(this, R.id.navHostFragment)

このIDは、Navigation Graph XMLファイルのfragmentタグの下に指定したIDです。currentDestination.label必要に応じて比較することもできます。


4

実用的な解決策が見つかりました。

private fun getCurrentFragment(): Fragment? {
    val currentNavHost = supportFragmentManager.findFragmentById(R.id.nav_host_id)
    val currentFragmentClassName = ((this as NavHost).navController.currentDestination as FragmentNavigator.Destination).className
    return currentNavHost?.childFragmentManager?.fragments?.filterNotNull()?.find {
        it.javaClass.name == currentFragmentClassName
    }
}

4

私の要件は、親アクティビティから現在表示されているフラグメントを取得することです。私の解決策は

 private LoginFragment getCurrentVisibleFragment() {
        NavHostFragment navHostFragment = (NavHostFragment)getSupportFragmentManager().getPrimaryNavigationFragment();
        FragmentManager fragmentManager = navHostFragment.getChildFragmentManager();
        Fragment loginFragment = fragmentManager.getPrimaryNavigationFragment();
        if(loginFragment instanceof LoginFragment){
            return (LoginFragment)loginFragment;
        }
        return null;
    }

これは、同じ問題を抱えている人を助けるかもしれません。


Kotlin langを取得しましたか?
IgorGanapolsky

1
これは私にとって完璧に機能しますが、他の答えがどうなっているのかわかりませんか?以前は機能しなかったかもしれませんが、今では魅力のように機能します。
ウェス

3

を使用するアクティビティから、NavHostFragment以下のコードを使用してのインスタンスを取得できますActive Fragment

val fragmentInstance = myNavHostFragment?.childFragmentManager?.primaryNavigationFragment

2

@slhddnの回答とコメントによると、これは私がそれを使用し、nav_graph.xmlファイルからフラグメントIDを取得する方法です。

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    setSupportActionBar(findViewById(R.id.toolbar))

    val navController = findNavController(this, R.id.nav_host_fragment)

    ivSettingsCog.setOnClickListener {

        if (navController.currentDestination?.id == R.id.updatesFragment) // Id as per set up on nav_graph.xml file
        {
            navController.navigate(R.id.action_updatesFragment_to_settingsFragment)
        }

    }

}

}

1

getChildFragmentManager()電話で ご確認いただけますか

NavHostFragment fragment = supportFragmentManager.findFragmentById(R.id.nav_host);
MyFragment frag = (MyFragment) fragment.getChildFragmentManager().findFragmentByTag(tag);

1

作る:

•フラグメントの一部のボタン:

val navController = findNavController(this)
  navController.popBackStack()

•アクティビティonBackPressed()

override fun onBackPressed() {
        val navController = findNavController(R.id.nav_host_fragment)
        val id = navController.currentDestination?.getId()
        if (id == R.id.detailMovieFragment){
            navController.popBackStack()
            return
        }

        super.onBackPressed()
    } 

1

フラグメントのインスタンスが必要な場合は、次の方法で行うことができます。

(活動)=> supportFragmentManager.fragments.first().childFragmentManager.fragments.first()

それは非常に醜いですが、そこからあなたはそれがあなたが遊んでみたいフラグメントのインスタンスであるかどうかをチェックすることができます


1

Androidxでは、から必要なフラグメントを見つけるために多くの方法を試しましたNavHostFragment。最後に私は以下の方法でそれを割ることができました

public Fragment getFunctionalFragment (String tag_name)
{
    NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
    FragmentManager navHostManager = Objects.requireNonNull(navHostFragment).getChildFragmentManager();

    Fragment fragment=null;
    List fragment_list = navHostManager.getFragments();

    for (int i=0; i < fragment_list.size() ; i ++ )
    {
        if ( fragment_list.get(i) instanceof HomeFragment && tag_name.equals("frg_home")) {
            fragment = (HomeFragment) fragment_list.get(i);
            break;
        }
    }

    return fragment;
}

1
SOへようこそ!回答を投稿する前に、確認してください...コードが明確ではありません。別の問題:コードを持ってくるだけの場合は、ソリューションを少し説明します。回答が16個ある場合は最大になるため、回答の長所を説明する必要があります。
デビッド・ガルシアBodego

1

navhostフラグメントの最初のフラグメントは現在のフラグメントです

Fragment navHostFragment = getSupportFragmentManager().getPrimaryNavigationFragment();
if (navHostFragment != null) 
{Fragment fragment = navHostFragment.getChildFragmentManager().getFragments().get(0);}

あなたの答えについてもう少し詳しく教えていただけますか?たぶんあなたのコードを説明することによって。
20

コードのみの回答はお勧めしません。あなたの答えが問題を解決する理由と方法を説明してください。
イゴールF.20年

1

まず、現在のフラグメントをIDで取得し、次にそのIDに応じてフラグメントを見つけることができます。

int id = navController.getCurrentDestination().getId();
Fragment fragment = getSupportFragmentManager().findFragmentById(id);

0

AndreiToadersの回答MukulBhardwajsの回答OnBackStackChangedListener。と組み合わせました。

属性として:

private FooFragment fragment;

私の中で onCreate

NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host);
FragmentManager navHostManager = Objects.requireNonNull(navHostFragment).getChildFragmentManager();
FragmentManager.OnBackStackChangedListener listener = () -> {
        List<Fragment> frags = navHostManager.getFragments();
        if(!frags.isEmpty()) {
            fragment = (FooFragment) frags.get(0);
        }
};
navController.addOnDestinationChangedListener((controller, destination, arguments) -> {
        if(destination.getId()==R.id.FooFragment){
            navHostManager.addOnBackStackChangedListener(listener);
        } else {
            navHostManager.removeOnBackStackChangedListener(listener);
           fragment = null;
        }
});

このようにして、後で表示されるフラグメントを取得できます。ただしfrags、ループして複数のフラグメントをinstanceof。でチェックできる場合もあります。


0

下部のナビゲーションビューを設定するためにこれを行う必要があり、次のようにしました。

val navController = Navigation.findNavController(requireActivity(), R.id.nav_tabs_home)
        val bottomNavBar: BottomNavigationView = nav_content_view
        NavigationUI.setupWithNavController(bottomNavBar, navController)

0

これを実現する最良の方法は、フラグメントライフサイクルコールバックを登録することです。

元の質問によると、あなたNavHostFragmentが次のように定義されている場合...

<fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/nav_host"
        app:navGraph= "@navigation/nav_item"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:defaultNavHost= "true"
        />

それからあなたの主な活動でonCreate(..)...

nav_host.childFragmentManager.registerFragmentLifecycleCallbacks(
    object:FragmentManager.FragmentLifecycleCallbacks() {
        override fun onFragmentViewCreated(
            fm: FragmentManager, f: Fragment, v: View,
            savedInstanceState: Bundle?
        ) {
            // callback method always called whenever a
            // fragment is added, or, a back-press returns
            // to the start-destination
        }
    }
)

要件に合わせて、他のコールバックメソッドがオーバーライドされる場合があります。


0

このソリューションはほとんどの状況で機能しますこれを試してください:

val mainFragment = fragmentManager?.primaryNavigationFragment?.parentFragment?.parentFragment as MainFragment

またはこれ:

val mainFragment = fragmentManager?.primaryNavigationFragment?.parentFragment as MainFragment

0

このコードは私から動作します

NavDestination current = NavHostFragment.findNavController(getSupportFragmentManager().getPrimaryNavigationFragment().getFragmentManager().getFragments().get(0)).getCurrentDestination();

switch (current.getId()) {
    case R.id.navigation_saved:
        // WRITE CODE
        break;
}

0

これは私のために働きます

(navController.currentDestination as FragmentNavigator.Destination).className 

それはcanonicalNameあなたの断片を返します


1
リフレクションのようなこのルックス
IgorGanapolsky

0

これは遅いかもしれませんが、後で誰かを助けるかもしれません。

ネストされたナビゲーションを使用している場合は、KotlinでこのようなIDを取得できます

val nav = Navigation.findNavController(requireActivity(), R.id.fragment_nav_host).currentDestination

これはfragment_nav_host.xmlのフラグメントの1つです

<fragment
    android:id="@+id/sampleFragment"
    android:name="com.app.sample.SampleFragment"
    android:label="SampleFragment"
    tools:layout="@layout/fragment_sample" />

このように必要なものをすべてチェックできます

if (nav.id == R.id.sampleFragment || nav.label == "SampleFragment"){}

0

最後に、まだ検索している人のための実用的なソリューション実際にはそれは非常に簡単であり、コールバックを使用してこれを達成することができます。

次の手順を実行します:

  1. アクティビティonCreate()からインスタンスを取得するフラグメント内にリスナーを作成します

    public class HomeFragment extends Fragment {
    
    private OnCreateFragment createLIstener;
    
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        createLIstener.onFragmentCreated(this);
        View root = inflater.inflate(R.layout.fragment_home, container, false);
        //findViews(root);
        return root;
    }
    
    @Override
    public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        inflater.inflate(R.menu.menu_main, menu);
    
    }
    
    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        if (item.getItemId()==R.id.action_show_filter){
            //do something
        }
        return super.onOptionsItemSelected(item);
    }
    
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try {
            createLIstener = (OnCreateFragment) context;
        } catch (ClassCastException e) {
            throw new ClassCastException(context.toString() + " must implement OnArticleSelectedListener");
            }
        }
    
        public interface OnCreateFragment{
            void onFragmentCreated(Fragment f);
        }
    }
    
  2. ホストのフラグメント/アクティビティにリスナーを実装します

    public class MainActivity extends AppCompatActivity implements HomeFragment.OnCreateFragment {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            BottomNavigationView navView = findViewById(R.id.nav_view);
           // Passing each menu ID as a set of Ids because each
           // menu should be considered as top level destinations.
            AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
                    R.id.navigation_home,
                    R. ----)
            .build();
            NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
            NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
            NavigationUI.setupWithNavController(navView, navController);
        }
    
        @Override
        public void onFragmentCreated(Fragment f) {
            if (f!=null){
                H.debug("fragment created listener: "+f.getId());
                f.setHasOptionsMenu(true);
            }else {
                H.debug("fragment created listener: NULL");
            }
        }
    }
    

そして、それはあなたが仕事をするために必要なすべてです。これが誰かを助けることを願っています


0

1つのフラグメント、Kotlin、ナビゲーションの使用法で理解できる最善の方法:

レイアウトファイルに次のタグを追加します: "android:tag =" main_fragment_tag ""

<fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/nav_host"
        app:navGraph= "@navigation/nav_item"
        android:tag="main_fragment_tag"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:defaultNavHost= "true"
        />

あなたの活動について:

val navHostFragment = supportFragmentManager.findFragmentByTag("main_fragment_tag") as NavHostFragment
val mainFragment = navHostFragment.childFragmentManager.fragments[0] as MainFragment
mainFragment.mainFragmentMethod()


-2

アクティビティでフラグメントオブジェクトを定義します。そして、各フラグメントから、フラグメントオブジェクトを渡すことによってこのメソッドを呼び出します。たとえば、静的フラグメントオブジェクトは、現在表示されているフラグメントによって毎回オーバーライドされます。

//method in MainActivity
private static Fragment fragment;

public void setFragment(Fragment fragment){
this.fragment = fragment;
}

//And from your fragment class, you can call
((<yourActivity in which fragment present>)getActivity()).setFragment(<your fragment object>);

//if you want to set it directly;
 ((<yourActivity in which fragment present>)getActivity()).fragment=<your fragment object>;

より良いアプローチのために、フラグメントからアクティビティへのコールバックを設定して、現在のフラグメントオブジェクトを渡すこともできます。


2
お時間をいただきありがとうございます。ナビゲーションコンポーネント自体から使用するものを探していました。
アリン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.