Android导航架构组件-获取当前可见的片段

时间:2018-07-17 15:20:53

标签: android android-navigation android-jetpack

在尝试导航组件之前,我曾经手动进行片段事务处理,并使用fragment标签来获取当前片段。

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`。

谢谢。

32 个答案:

答案 0 :(得分:23)

我设法找到了一种方法,如下所示:

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

当然,您知道这是第一个片段。我仍在研究没有这种方法。我同意这不是最好的方法,但目前应该是这样。

答案 1 :(得分:14)

我找不到找到当前片段实例的方法。但是,您可以使用以下代码获取最近添加的片段的ID。

navController.getCurrentDestination().getId()

它返回导航文件中的ID。希望这会有所帮助。

答案 2 :(得分:10)

您应该查看导航片段的childFragmentManager primaryNavigationFragment属性,这是引用当前显示的片段的地方。

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

答案 3 :(得分:7)

这似乎是最干净的解决方案。

1。创建以下扩展名

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

fun FragmentManager.getCurrentNavigationFragment(): Fragment? =
    primaryNavigationFragment?.childFragmentManager?.fragments?.first()

2。在ActivityNavHostFragment中像这样使用它:

val currentFragment = supportFragmentManager.getCurrentNavigationFragment()

答案 4 :(得分:4)

我的要求是从Parent活动中获取当前可见的片段,我的解决方案是

 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;
    }

这可能会帮助某些遇到相同问题的人。

答案 5 :(得分:2)

找到了可行的解决方案。

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
    }
}

答案 6 :(得分: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)
        }

    }

}

}

答案 7 :(得分:1)

在您的活动中,托管 NavHostFragment 我们可以编写以下代码段来获取当前显示的片段的实例

Fragment fragment = myNavHostFragment.getChildFragmentManager().findFragmentById(R.id.navHostFragmentId)
if(fragment instanceOf MyFragment) {
  //Write your code here
}

此处R.id.navHostFragmentId 是活动 xml 中 NavHostFragment 的 resId

答案 8 :(得分:1)

请致电getChildFragmentManager()

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

答案 9 :(得分:1)

navhost片段中的第一个片段是当前片段

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

答案 10 :(得分:1)

navController().currentDestination?.id

将为您提供当前Fragment的ID

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

此ID是您在Navigation Graph XML文件中的fragment标签下提供的ID。如果需要,您还可以比较currentDestination.label

答案 11 :(得分:1)

如果需要片段的实例,可以使用:

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

非常非常很丑,但是从那里您可以检查它是否是要播放的片段的一个实例

答案 12 :(得分:1)

这可能要晚了,但对于仍在寻找的人

val currentfraagment=NavHostFragment.findNavController(nav_host_fragment).currentDestination!!.id

然后您可以做类似的事情

if(currentfraagment == R.id.myFragemnt){
     //do something
}

请注意,这是针对kotlin的,java代码应该几乎相同

答案 13 :(得分:0)

这对我有用

(navController.currentDestination as FragmentNavigator.Destination).className 

它将返回您片段的canonicalName

答案 14 :(得分:0)

在您的活动中定义一个片段对象。然后通过传递片段对象从每个片段调用此方法,例如 因此,静态片段对象每次都会被当前显示的片段覆盖。

FileUtils.cleanDirectory(file);

您还可以设置从片段到活动的回调,以获得更好的方法并传递当前的片段对象。

答案 15 :(得分:0)

这是我的java解决方案

    NavHostFragment  navHostFragment= (NavHostFragment) getSupportFragmentManager().getFragments().get(0);
    MyFragment  fragment = (MyFragment) navHostFragment.getChildFragmentManager().getFragments().get(0);
    fragment.doSomething();

答案 16 :(得分:0)

使用导航组件,我使用这行代码获得了当前显示的片段:

  storage = file.Storage('storage.dat')
  credentials = storage.get()
  if credentials is None or credentials.invalid:
    credentials = tools.run_flow(flow, storage, flags)
  http = credentials.authorize(http=httplib2.Http())

答案 17 :(得分:0)

val fragment: YourFragment? = yourNavHost.findFragment()

注意:findFragment扩展功能位于androidx.fragment.app包中,它是通用功能

答案 18 :(得分: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()

答案 19 :(得分: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. 在主机Fragment / Activity中实现监听器

    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");
            }
        }
    }
    

这就是完成这项工作所需的一切。 希望对某人有帮助

答案 20 :(得分:0)

这可能会迟到,但可能会在以后帮助某个人。

如果您使用嵌套导航,则可以在Kotlin中获得这样的ID

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

这是fragment_nav_host.xml中的片段之一

<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"){}

答案 21 :(得分:0)

在有addOnDestinationChangedListener的活动中使用NavHostFragment

 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());
            }
        });

答案 22 :(得分:0)

首先,通过ID获取当前片段,然后根据该ID找到该片段。

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

答案 23 :(得分:0)

此解决方案在大多数情况下均适用 试试这个:

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

或者这个:

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

答案 24 :(得分:0)

此代码对我有效

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

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

答案 25 :(得分:0)

从使用NavHostFragment的活动中,您可以使用下面的代码来检索Active Fragment的实例。

val fragmentInstance = myNavHostFragment?.childFragmentManager?.primaryNavigationFragment

答案 26 :(得分:0)

我将Andrei Toaders answerMukul Bhardwajs answerOnBackStackChangedListener组合在一起。

作为属性:

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检查多个片段。

答案 27 :(得分:0)

在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;
}

答案 28 :(得分:0)

我需要执行此操作以设置底部导航视图,并且我这样做是这样的:

.git

答案 29 :(得分:0)

制作:

•在片段的某些按钮中:

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()
    } 

答案 30 :(得分: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
        }
    }
)

其他回调方法可能会被覆盖以满足您的要求。

答案 31 :(得分:-1)

要获取当前片段,可以调用getPrimaryNavigationFragment()方法

Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.nav_host)
    .getChildFragmentManager().getPrimaryNavigationFragment();