如何检索 NavHostFragment 中的当前片段?
How I can retrieve current fragment in NavHostFragment?
我试图在新的导航组件中找到一种方法,但我没有找到任何相关信息。
我有当前目的地:
mainHostFragment.findNavController().currentDestination
但我无法获得对显示片段的任何引用。
导航不提供任何机制来获取当前目的地的实现(即片段本身)。
根据 Creating event callbacks to the activity,您应该通过
与您的片段通信
- 让片段在其
onAttach
方法中注册回调,将您的 Activity 转换为您提供的接口实例
- Use a shared
ViewModel
您的 Activity 和 Fragment 用于通信。
你可以这样做:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val navHostFragment = supportFragmentManager.fragments.first() as? NavHostFragment
if(navHostFragment != null) {
val childFragments = navHostFragment.childFragmentManager.fragments
childFragments.forEach { fragment ->
fragment.onActivityResult(requestCode, resultCode, data)
}
}
}
但为了更高级的通信具有回调方法的监听器在Fragment.onAttach()中注册(Fragment -> Activity rather one direction communication
)和 SharedViewModel(bidirectional
,重要的是 ViewModelProviders, and Lifecycle owner that is scoped to getActivity()
)
使用 Michal 的回答我写了这个扩展函数用于测试:
@Suppress("UNCHECKED_CAST")
fun <F : Fragment> AppCompatActivity.getFragment(fragmentClass: Class<F>): F? {
val navHostFragment = this.supportFragmentManager.fragments.first() as NavHostFragment
navHostFragment.childFragmentManager.fragments.forEach {
if (fragmentClass.isAssignableFrom(it.javaClass)) {
return it as F
}
}
return null
}
这样使用:
val myFragment = activity.getFragment(MyFragment::class.java)
对显示片段的引用(AndroidX):
java
public Fragment getForegroundFragment(){
Fragment navHostFragment = getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
return navHostFragment == null ? null : navHostFragment.getChildFragmentManager().getFragments().get(0);
}
科特林
val navHostFragment: Fragment? =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment)
navHostFragment?.childFragmentManager?.fragments?.get(0)
这里nav_host_fragment
是一个ID
您的 activity_main.xml
中的 fragment
标签与 android:name="androidx.navigation.fragment.NavHostFragment"
基于其他答案
Fragment navHostFragment = getSupportFragmentManager().getPrimaryNavigationFragment();
Fragment fragment = navHostFragment.getChildFragmentManager().getFragments().get(0);
((Your Fragment Class) fragment).(public method inside the fragment)
对我有用
从具有 NavHostFragment 的 Activity 中,可以使用以下代码片段检索活动片段的实例。
科特林
val currentFragment
= mNavHostFragment?.childFragmentManager?.primaryNavigationFragment
java
Fragment navHostFragment = getSupportFragmentManager().getPrimaryNavigationFragment();
Fragment currentFragment = navHostFragment.getChildFragmentManager().getFragments().get(0);
你可以这样做:
@Override
public void onBackPressed() {
super.onBackPressed();
NavController navController = Navigation.findNavController(this, R.id.fragment);
int id=navController.getCurrentDestination().getId();
if(id == R.id.startGameFragment ){
selectedPosition(0);
} else if(id == R.id.gameFragment ){
selectedPosition(1);
} else if(id == R.id.endGameFragment){
selectedPosition(2);
}
}
private void selectedPosition(int pos){
for (int i = 0; i >=nav_view.getMenu().size(); i++) {
nav_view.getMenu().getItem(pos).setChecked(false);
}
nav_view.getMenu().getItem(pos).setChecked(true);
}
我post我对androidx的完整回答。 注意:在我的情况下,我需要检索其中一个子片段(不能是第一个)。
在 MainActivity 中你应该有这样的东西:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.mytest, R.id.nav_help)
.setDrawerLayout(drawer)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
...
然后你必须创建一个方法来检索好的片段。
private MyTestFragment getMyTestFragment(){
MyTestFragment resultFragment = null;
Fragment navHostFragment = getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
if(navHostFragment != null && navHostFragment.getChildFragmentManager() != null) {
List<Fragment> fragmentList = navHostFragment.getChildFragmentManager().getFragments();
for (Fragment fragment : fragmentList) {
if (fragment instanceof MyTest) {
resultFragment = (MyTest) fragment;
break;
}
}
}
return resultFragment;
}
终于明白了。
真正处理这个问题的最佳和正确方法是使用接口。视图模型应该真正用于在 activity 和片段之间传递数据。这是我解决这个问题的方法:
创建界面
interface NavigationInterface {
fun referenceCourseListFragment(fragment: CourseListFragment)
fun referenceCouseDetailFragment(fragment: CourseDetailInfoFragment)
}
确保activity实现接口
class NotesActivity : AppCompatActivity(), NavigationInterface {}
确保为每个需要引用的片段创建 lateinit var,然后
private lateinit var courseListFragment: CourseListFragment
private lateinit var courseDetailInfoFragment: CourseDetailInfoFragment
现在在 onCreateView 方法中的每个片段中,确保创建接口侦听器并使用接口回传片段
private lateinit var navigationInterface: NavigationInterface
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
//establish interface communication
activity?.let {
instantiateNavigationInterface(it)
}
// Inflate the layout for this fragment
fragmentView = inflater.inflate(R.layout.fragment_course_list, container,
false)
navigationInterface.referenceCourseListFragment(this)
return fragmentView
}
现在回到 activity,您应该能够通过接口回调实例化您的片段对象以供参考
override fun referenceCourseListFragment(fragment: CourseListFragment) {
courseListFragment = fragment
}
override fun referenceCouseDetailFragment(fragment: CourseDetailInfoFragment)
{
courseDetailInfoFragment = fragment
}
我认为有可能出现异常,因此您可以使用接口回调,这是从一端到另一端通信的可靠方法,只需通过下面代码的引用检查。
Fragment A(){ interface ClickPostItemListener {
fun onClicked(position: Int)
}
val itemListener = object : ClickPostItemListener{
override fun onClicked(position: Int) {
postBackNForth(position)
}
} } Fragment B(clickItem:ClickPostItemListener ){ clickItem() }
我试图在新的导航组件中找到一种方法,但我没有找到任何相关信息。
我有当前目的地:
mainHostFragment.findNavController().currentDestination
但我无法获得对显示片段的任何引用。
导航不提供任何机制来获取当前目的地的实现(即片段本身)。
根据 Creating event callbacks to the activity,您应该通过
与您的片段通信- 让片段在其
onAttach
方法中注册回调,将您的 Activity 转换为您提供的接口实例 - Use a shared
ViewModel
您的 Activity 和 Fragment 用于通信。
你可以这样做:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val navHostFragment = supportFragmentManager.fragments.first() as? NavHostFragment
if(navHostFragment != null) {
val childFragments = navHostFragment.childFragmentManager.fragments
childFragments.forEach { fragment ->
fragment.onActivityResult(requestCode, resultCode, data)
}
}
}
但为了更高级的通信具有回调方法的监听器在Fragment.onAttach()中注册(Fragment -> Activity rather one direction communication
)和 SharedViewModel(bidirectional
,重要的是 ViewModelProviders, and Lifecycle owner that is scoped to getActivity()
)
使用 Michal 的回答我写了这个扩展函数用于测试:
@Suppress("UNCHECKED_CAST")
fun <F : Fragment> AppCompatActivity.getFragment(fragmentClass: Class<F>): F? {
val navHostFragment = this.supportFragmentManager.fragments.first() as NavHostFragment
navHostFragment.childFragmentManager.fragments.forEach {
if (fragmentClass.isAssignableFrom(it.javaClass)) {
return it as F
}
}
return null
}
这样使用:
val myFragment = activity.getFragment(MyFragment::class.java)
对显示片段的引用(AndroidX):
java
public Fragment getForegroundFragment(){
Fragment navHostFragment = getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
return navHostFragment == null ? null : navHostFragment.getChildFragmentManager().getFragments().get(0);
}
科特林
val navHostFragment: Fragment? =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment)
navHostFragment?.childFragmentManager?.fragments?.get(0)
这里nav_host_fragment
是一个ID
您的 activity_main.xml
中的 fragment
标签与 android:name="androidx.navigation.fragment.NavHostFragment"
基于其他答案
Fragment navHostFragment = getSupportFragmentManager().getPrimaryNavigationFragment();
Fragment fragment = navHostFragment.getChildFragmentManager().getFragments().get(0);
((Your Fragment Class) fragment).(public method inside the fragment)
对我有用
从具有 NavHostFragment 的 Activity 中,可以使用以下代码片段检索活动片段的实例。
科特林
val currentFragment = mNavHostFragment?.childFragmentManager?.primaryNavigationFragment
java
Fragment navHostFragment = getSupportFragmentManager().getPrimaryNavigationFragment();
Fragment currentFragment = navHostFragment.getChildFragmentManager().getFragments().get(0);
你可以这样做:
@Override
public void onBackPressed() {
super.onBackPressed();
NavController navController = Navigation.findNavController(this, R.id.fragment);
int id=navController.getCurrentDestination().getId();
if(id == R.id.startGameFragment ){
selectedPosition(0);
} else if(id == R.id.gameFragment ){
selectedPosition(1);
} else if(id == R.id.endGameFragment){
selectedPosition(2);
}
}
private void selectedPosition(int pos){
for (int i = 0; i >=nav_view.getMenu().size(); i++) {
nav_view.getMenu().getItem(pos).setChecked(false);
}
nav_view.getMenu().getItem(pos).setChecked(true);
}
我post我对androidx的完整回答。 注意:在我的情况下,我需要检索其中一个子片段(不能是第一个)。
在 MainActivity 中你应该有这样的东西:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.mytest, R.id.nav_help)
.setDrawerLayout(drawer)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
...
然后你必须创建一个方法来检索好的片段。
private MyTestFragment getMyTestFragment(){
MyTestFragment resultFragment = null;
Fragment navHostFragment = getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
if(navHostFragment != null && navHostFragment.getChildFragmentManager() != null) {
List<Fragment> fragmentList = navHostFragment.getChildFragmentManager().getFragments();
for (Fragment fragment : fragmentList) {
if (fragment instanceof MyTest) {
resultFragment = (MyTest) fragment;
break;
}
}
}
return resultFragment;
}
终于明白了。
真正处理这个问题的最佳和正确方法是使用接口。视图模型应该真正用于在 activity 和片段之间传递数据。这是我解决这个问题的方法:
创建界面
interface NavigationInterface {
fun referenceCourseListFragment(fragment: CourseListFragment)
fun referenceCouseDetailFragment(fragment: CourseDetailInfoFragment)
}
确保activity实现接口
class NotesActivity : AppCompatActivity(), NavigationInterface {}
确保为每个需要引用的片段创建 lateinit var,然后
private lateinit var courseListFragment: CourseListFragment
private lateinit var courseDetailInfoFragment: CourseDetailInfoFragment
现在在 onCreateView 方法中的每个片段中,确保创建接口侦听器并使用接口回传片段
private lateinit var navigationInterface: NavigationInterface
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
//establish interface communication
activity?.let {
instantiateNavigationInterface(it)
}
// Inflate the layout for this fragment
fragmentView = inflater.inflate(R.layout.fragment_course_list, container,
false)
navigationInterface.referenceCourseListFragment(this)
return fragmentView
}
现在回到 activity,您应该能够通过接口回调实例化您的片段对象以供参考
override fun referenceCourseListFragment(fragment: CourseListFragment) {
courseListFragment = fragment
}
override fun referenceCouseDetailFragment(fragment: CourseDetailInfoFragment)
{
courseDetailInfoFragment = fragment
}
我认为有可能出现异常,因此您可以使用接口回调,这是从一端到另一端通信的可靠方法,只需通过下面代码的引用检查。
Fragment A(){ interface ClickPostItemListener { fun onClicked(position: Int) }
val itemListener = object : ClickPostItemListener{ override fun onClicked(position: Int) { postBackNForth(position) } } } Fragment B(clickItem:ClickPostItemListener ){ clickItem() }