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

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

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,我想检索我所显示的“我的碎片”。

谢谢你。

116252 次浏览

你能帮我查一下 getChildFragmentManager()的电话吗

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

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

navController.currentDestination?.getId()

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

在你的活动中定义一个片段对象。并且从每个片段通过传递片段对象来调用这个方法,如 因此,静态片段对象将被当前每次显示片段所覆盖。

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

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

我暂时找到了一种方法,它是这样的:

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

如果你知道这是第一个碎片。我还在研究没有这个的方法。我同意这不是最好的方式,但这应该是现在的东西。

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

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

找到解决办法了。

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

在有 NavHostFragment的活动中使用 addOnDestinationChangedListener

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

为了科特林

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


}

这可能有点晚了,但对于任何还在寻找的人来说

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

然后你就可以

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

请注意,这是为 kotlin,Java 代码应该几乎相同

我把 安德烈・托德回答Mukul Bhardwajs 回答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

我需要这样设置一个底部导航视图,我是这样做的:

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

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

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

这似乎是最干净的解决方案。改变扩展功能的属性。感谢 伊戈尔 · 沃伊达

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

实现这一点的最佳方法是注册一个 片段生命周期回调

根据最初的问题,如果你的 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
}
}
)

可以重写其他回调方法以满足您的需求。

制作:

•在你片段中的某个按钮上:

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

•在活动中使用 BackPress ()

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

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

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

它的 非常丑陋,但从那里你可以检查它是否是一个片段的实例,你想玩

在 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;
}
navController().currentDestination?.id

会给你你当前的 Fragment的 ID 在哪里

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


这个 id 是您在 fragment标记下的 Navigation Graph XML文件中给出的 id。如果你愿意,你也可以比较 currentDestination.label

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

val fragmentInstance = myNavHostFragment?.childFragmentManager?.primaryNavigationFragment

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

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

这个密码是我的

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


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

这个解决方案在大多数情况下都有效 试试这个:

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

或者这样:

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

这对我有用

(navController.currentDestination as FragmentNavigator.Destination).className

它会返回你片段的 canonicalName

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

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

这可以帮助一些有同样问题的人。

这可能是晚了,但可能有人以后帮助。

如果你使用嵌套导航,你可以在 Kotlin 得到这样的 id

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

这是片段 _ 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"){}

根据@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. 在您希望从 activity 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");
    }
    }
    }
    

这就是你完成这项工作所需要的一切。 跳上来帮帮忙

我能找到的最好的方法是使用1个片段,Kotlin,导航用法:

在您的布局文件中添加标记: “ android: tag = “ main _ Frag_ 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()
val fragment: YourFragment? = yourNavHost.findFragment()

注意: findFragment扩展函数位于 androidx.fragment.app包中,是通用函数

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

val fragment = parentFragmentManager.primaryNavigationFragment

这是我对 Java 的解决方案

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

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

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

这里的 < strong > R.id.navHostFragmentId 是您的活动 xml 中 NavHostFragment 的 resId

在片段管理器上创建扩展函数

inline fun <reified T : Fragment> FragmentManager.findNavFragment(hostId: Int): T? {


val navHostFragment = findFragmentById(hostId)


return navHostFragment?.childFragmentManager?.fragments?.findLast {
it is T
} as T?
}

现在只需要通过给出宿主片段的 id 来使用它,并获取指定的片段

    val myFragment: MyFragment? = supportFragmentManager.findNavFragment<MyFragment>(R.id.nav_host_id)

Activity类中添加以下方法:

private Fragment getCurrentFragment() {
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager()
.findFragmentById(R.id.nav_host);
if (navHostFragment != null) return navHostFragment.getChildFragmentManager()
.getPrimaryNavigationFragment();
return null;
}

这是解决你问题的最简单明了的方法。

希望能有帮助!

在导航图中获取当前活动片段的 Kotlin 版本代码

fun getCurrentFragmentInstance(activity: HomeActivity): Fragment? {
val navHostFragment =
activity.supportFragmentManager.primaryNavigationFragment as NavHostFragment?
val fragmentManager: FragmentManager = navHostFragment!!.childFragmentManager
return fragmentManager.primaryNavigationFragment
}

我在应用程序里做的和这些答案有点不一样

  1. 我在类 myClass (myClass.kt)中创建了全局变量

    字符串 = “ defaultValue”

  2. 在片段中更新时(TagsFragment.kt)

    CurrentFragmentName = “ tagsFragment”

  3. 在我的例子中是后退按钮(在 TagsFragment.kt 的父活动中)

    D (TAG,myClass.currentFragmentName) Val home 片段 = HomeFragment () 如果(InTory.currentFragmentName = = “ tagsFragment”){ SetCurrentFragment (homeFragment,“片段 _ tag _ home”) }