使用 ActionBar 进入 SettingsFragment 后无法返回主片段
Cannot go back to Main Fragment after going into SettingsFragment using ActionBar
希望大家平安。我在使用 ActionBar 和 ActionBar 中的向上按钮时遇到了一个令人沮丧的问题。我的应用程序中有以下片段结构:
MainFragment -
|- SettingsFragment -
|- GeneralSettingsFragment
|- ScaryStuffSettingsFragment
上面的所有片段都启用了 ActionBar。 SettingsFragment、GeneralSettingsFragment 和 ScaryStuffFragment 都启用了向上按钮,这样用户就可以按上面的顺序在需要时返回。
在我的 MainFragment 中,我有以下代码可以访问 SettingsFragment:
override fun onOptionsItemSelected(item: MenuItem): Boolean {
super.onOptionsItemSelected(item)
when(item.itemId) {
R.id.action_main_to_settings_menu -> {
onOptionSettingsClick()
}
}
return true
}
/** When the user taps the options menu settings button, we'll take them to the
* settings menu.
*/
private fun onOptionSettingsClick() {
findNavController().navigate(R.id.settingsFragment)
}
在我的 SettingsFragment 中有以下内容:
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when(item.itemId) {
android.R.id.home -> findNavController().navigateUp()
}
return super.onOptionsItemSelected(item)
}
SettingsFragment 中使用的代码与 ScaryStuffSettingsFragment 和 GeneralSettingsFragment 中使用的代码相同。
现在,当我点击 MainFragment 中的设置时,它会将我带到 SettingsFragment。那里没有问题。如果我再次点击 SettingsFragment ActionBar 中的向上按钮,它会将我发送到 MainFragment。
如果我点击恐怖的东西或一般设置,我会毫无问题地转到相关的片段。如果我点击任一片段中的向上按钮,它会将我带到 SettingsFragment。再次。这里没问题。
但是,如果我想在使用向上按钮点击可怕的东西或常规后从 SettingsFragment 返回 MainFragment...什么都没有发生。
我发现,如果我点击设备本身的后退按钮,它会带我回到 MainFragment,从而完全规避了问题,但我不希望用户在大多数情况下都使用向上按钮设置,然后必须点击后退按钮(如果有意义的话)。
一旦选择了其中一个子片段,它会“忘记”MainFragment 和 SettingsFragment 之间的传输,这是怎么回事?
谢谢!
编辑:
MainFragment 是一个普通片段。它的onCreateView如下:
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?,
savedInstance: Bundle?): View {
_binding = FragmentMainBinding.inflate(inflater, container, false)
setHasOptionsMenu(true)
return binding.root
}
我的所有三个设置应用程序都是 PreferenceFragments,因此具有以下内容:
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.general_settings_preferences, rootKey)
setHasOptionsMenu(true)
}
编辑 2:
我现在有以下内容:
主要活动:
override fun onCreate(savedInstanceState: Bundle?) {
navController = findNavController(R.id.nav_host)
appBarConfiguration = AppBarConfiguration.Builder(R.id.FragmentMain).build()
val hostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment_container) as NavHostFragment?
//navController = hostFragment?.navController!! // Commented out due to throwing a nullpointerexception
setupActionBarWithNavController(navController, appBarConfiguration)
}
override fun onSupportNavigateUp(): Boolean {
return (NavigationUI.navigateUp(navController, appBarConfiguration) || super.onSupportNavigateUp())
}
当我这样做时(也更新我的导航图),然后点击设置(进入我的 SettingsFragment)它短暂地显示 SettingsFragment 然后更改为顶部的设置(这是因为我告诉它用(activity as AppCompatActivity).supportActionBar?.title = getString(R.string.menu_option_settings)
在我的 onCreateOptionsMenu
方法中。然后,当我返回时,它按预期工作。但是,当我随后点击 Scary Stuff(转到 ScaryStuffSettingsFragment)或常规设置(转到 GeneralSettingsFragment)时它做同样的事情并在顶部闪烁片段的名称,然后更改为我设置的内容,当我点击向上箭头时,它会将我送回主片段。
我只希望设置菜单返回到 MainFragment,其他设置应该转到设置菜单(如果有意义的话)。
将 setHasOptionsMenu 添加到 onViewCreated
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setHasOptionsMenu(true)
}
if I then want to go back to MainFragment from
SettingsFragment once I have tapped either Scary Stuff or General
using the Up Button... Nothing happens.
没有任何反应意味着导航组件没有管理向上按钮的点击;显然你按照以下方式手动管理返回堆栈导航:
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when(item.itemId) {
android.R.id.home -> findNavController().navigateUp()
}
return super.onOptionsItemSelected(item)
}
为了解决这个问题,请确保在承载这些片段 (documentation reference) 的 activity 中添加启用 supportActionBar
导航:
- 调用 setupActionBarWithNavController()
- 覆盖
onSupportNavigateUp()
class MainActivity : AppCompatActivity() {
lateinit var navController: NavController
private lateinit var mAppBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mAppBarConfiguration = AppBarConfiguration.Builder(
R.id.main_fragment // Adjust that to your top level fragments (that you don't want the UP button appear)
).build()
val hostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment1) as NavHostFragment?
navController = hostFragment?.navController!!
setupActionBarWithNavController(this, navController)
}
override fun onSupportNavigateUp(): Boolean {
return (NavigationUI.navigateUp(navController, mAppBarConfiguration)
|| super.onSupportNavigateUp())
}
}
注意: 如果您没有使用默认 supportActionBar
,要启用导航组件控件您的自定义工具栏:
toolbar.setupWithNavController(navController, appBarConfiguration)
到目前为止,这使得 actionBar
及其导航由导航组件/navController
控制。并且通过UP按钮的导航会正常注册到backstack中。
但是要从任何导航操作的返回堆栈中删除一些片段,您可以使用 popUpTo
& popUpToInclusive
. 答案通过示例描述了不同之处。
将其应用到您的案例中;你通过从 SettingsFragment
到 GeneralSettingsFragment
|ScaryStuffSettingsFragment
的动作来做到这一点
在navGraph
:
<navigation ...>
....
<fragment
android:id="@+id/fragmentSettings"
android:name="com.example.android.ktnavarchcomptwoactivities.SettingsFragment"
android:label="fragmentSettings" >
<action
android:id="@+id/action_fragmentSettings_to_fragmentScaryStuffSettings"
app:destination="@id/fragmentScaryStuffSettings"
app:popUpTo="@id/fragment_main"
app:popUpToInclusive="false"/>
<action
android:id="@+id/action_fragmentSettings_to_fragmentGeneralSettings"
app:destination="@id/fragmentGeneralSettings"
app:popUpTo="@id/fragment_main"
app:popUpToInclusive="false"/>
</fragment>
</navigation>
或者通过在导航期间定义 NavOptions
参数以编程方式:
在 SettingsFragment 中:
// Navigation from SettingsFragment to GeneralSettingsFragment
findNavController().navigate(
R.id.action_fragmentSettings_to_fragmentGeneralSettings,
null,
NavOptions.Builder().setPopUpTo(R.id.fragment_main, false).build()
)
// Navigation from SettingsFragment to ScaryStuffSettingsFragment
findNavController().navigate(
R.id.action_fragmentSettings_to_fragmentScaryStuffSettings,
null,
NavOptions.Builder().setPopUpTo(R.id.fragment_main, false).build()
)
希望大家平安。我在使用 ActionBar 和 ActionBar 中的向上按钮时遇到了一个令人沮丧的问题。我的应用程序中有以下片段结构:
MainFragment -
|- SettingsFragment -
|- GeneralSettingsFragment
|- ScaryStuffSettingsFragment
上面的所有片段都启用了 ActionBar。 SettingsFragment、GeneralSettingsFragment 和 ScaryStuffFragment 都启用了向上按钮,这样用户就可以按上面的顺序在需要时返回。
在我的 MainFragment 中,我有以下代码可以访问 SettingsFragment:
override fun onOptionsItemSelected(item: MenuItem): Boolean {
super.onOptionsItemSelected(item)
when(item.itemId) {
R.id.action_main_to_settings_menu -> {
onOptionSettingsClick()
}
}
return true
}
/** When the user taps the options menu settings button, we'll take them to the
* settings menu.
*/
private fun onOptionSettingsClick() {
findNavController().navigate(R.id.settingsFragment)
}
在我的 SettingsFragment 中有以下内容:
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when(item.itemId) {
android.R.id.home -> findNavController().navigateUp()
}
return super.onOptionsItemSelected(item)
}
SettingsFragment 中使用的代码与 ScaryStuffSettingsFragment 和 GeneralSettingsFragment 中使用的代码相同。
现在,当我点击 MainFragment 中的设置时,它会将我带到 SettingsFragment。那里没有问题。如果我再次点击 SettingsFragment ActionBar 中的向上按钮,它会将我发送到 MainFragment。
如果我点击恐怖的东西或一般设置,我会毫无问题地转到相关的片段。如果我点击任一片段中的向上按钮,它会将我带到 SettingsFragment。再次。这里没问题。
但是,如果我想在使用向上按钮点击可怕的东西或常规后从 SettingsFragment 返回 MainFragment...什么都没有发生。
我发现,如果我点击设备本身的后退按钮,它会带我回到 MainFragment,从而完全规避了问题,但我不希望用户在大多数情况下都使用向上按钮设置,然后必须点击后退按钮(如果有意义的话)。
一旦选择了其中一个子片段,它会“忘记”MainFragment 和 SettingsFragment 之间的传输,这是怎么回事?
谢谢!
编辑:
MainFragment 是一个普通片段。它的onCreateView如下:
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?,
savedInstance: Bundle?): View {
_binding = FragmentMainBinding.inflate(inflater, container, false)
setHasOptionsMenu(true)
return binding.root
}
我的所有三个设置应用程序都是 PreferenceFragments,因此具有以下内容:
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.general_settings_preferences, rootKey)
setHasOptionsMenu(true)
}
编辑 2:
我现在有以下内容:
主要活动:
override fun onCreate(savedInstanceState: Bundle?) {
navController = findNavController(R.id.nav_host)
appBarConfiguration = AppBarConfiguration.Builder(R.id.FragmentMain).build()
val hostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment_container) as NavHostFragment?
//navController = hostFragment?.navController!! // Commented out due to throwing a nullpointerexception
setupActionBarWithNavController(navController, appBarConfiguration)
}
override fun onSupportNavigateUp(): Boolean {
return (NavigationUI.navigateUp(navController, appBarConfiguration) || super.onSupportNavigateUp())
}
当我这样做时(也更新我的导航图),然后点击设置(进入我的 SettingsFragment)它短暂地显示 SettingsFragment 然后更改为顶部的设置(这是因为我告诉它用(activity as AppCompatActivity).supportActionBar?.title = getString(R.string.menu_option_settings)
在我的 onCreateOptionsMenu
方法中。然后,当我返回时,它按预期工作。但是,当我随后点击 Scary Stuff(转到 ScaryStuffSettingsFragment)或常规设置(转到 GeneralSettingsFragment)时它做同样的事情并在顶部闪烁片段的名称,然后更改为我设置的内容,当我点击向上箭头时,它会将我送回主片段。
我只希望设置菜单返回到 MainFragment,其他设置应该转到设置菜单(如果有意义的话)。
将 setHasOptionsMenu 添加到 onViewCreated
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setHasOptionsMenu(true)
}
if I then want to go back to MainFragment from SettingsFragment once I have tapped either Scary Stuff or General using the Up Button... Nothing happens.
没有任何反应意味着导航组件没有管理向上按钮的点击;显然你按照以下方式手动管理返回堆栈导航:
override fun onOptionsItemSelected(item: MenuItem): Boolean { when(item.itemId) { android.R.id.home -> findNavController().navigateUp() } return super.onOptionsItemSelected(item) }
为了解决这个问题,请确保在承载这些片段 (documentation reference) 的 activity 中添加启用 supportActionBar
导航:
- 调用 setupActionBarWithNavController()
- 覆盖
onSupportNavigateUp()
class MainActivity : AppCompatActivity() {
lateinit var navController: NavController
private lateinit var mAppBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mAppBarConfiguration = AppBarConfiguration.Builder(
R.id.main_fragment // Adjust that to your top level fragments (that you don't want the UP button appear)
).build()
val hostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment1) as NavHostFragment?
navController = hostFragment?.navController!!
setupActionBarWithNavController(this, navController)
}
override fun onSupportNavigateUp(): Boolean {
return (NavigationUI.navigateUp(navController, mAppBarConfiguration)
|| super.onSupportNavigateUp())
}
}
注意: 如果您没有使用默认 supportActionBar
,要启用导航组件控件您的自定义工具栏:
toolbar.setupWithNavController(navController, appBarConfiguration)
到目前为止,这使得 actionBar
及其导航由导航组件/navController
控制。并且通过UP按钮的导航会正常注册到backstack中。
但是要从任何导航操作的返回堆栈中删除一些片段,您可以使用 popUpTo
& popUpToInclusive
.
将其应用到您的案例中;你通过从 SettingsFragment
到 GeneralSettingsFragment
|ScaryStuffSettingsFragment
在navGraph
:
<navigation ...>
....
<fragment
android:id="@+id/fragmentSettings"
android:name="com.example.android.ktnavarchcomptwoactivities.SettingsFragment"
android:label="fragmentSettings" >
<action
android:id="@+id/action_fragmentSettings_to_fragmentScaryStuffSettings"
app:destination="@id/fragmentScaryStuffSettings"
app:popUpTo="@id/fragment_main"
app:popUpToInclusive="false"/>
<action
android:id="@+id/action_fragmentSettings_to_fragmentGeneralSettings"
app:destination="@id/fragmentGeneralSettings"
app:popUpTo="@id/fragment_main"
app:popUpToInclusive="false"/>
</fragment>
</navigation>
或者通过在导航期间定义 NavOptions
参数以编程方式:
在 SettingsFragment 中:
// Navigation from SettingsFragment to GeneralSettingsFragment
findNavController().navigate(
R.id.action_fragmentSettings_to_fragmentGeneralSettings,
null,
NavOptions.Builder().setPopUpTo(R.id.fragment_main, false).build()
)
// Navigation from SettingsFragment to ScaryStuffSettingsFragment
findNavController().navigate(
R.id.action_fragmentSettings_to_fragmentScaryStuffSettings,
null,
NavOptions.Builder().setPopUpTo(R.id.fragment_main, false).build()
)