Is it possible to use Android Jetpack Navigation Component to navigate the fragments of a Settings Preferences? I have a Settings screens with multiple nested Preference Fragments. I was wondering if it is feasible to use Android Jetpack Navigation Component to facilitate my task?
The google documentation states that hierarchical nesting of preferences are now deprecated in favour of inter-fragment navigation; that is the structure <PreferencesScreen> ... <PreferencesScreen ...> ... </PreferenceScreen> ... </PreferenceScreen>
is now out.
The documents propose that one replace the nested <PreferenceScreen/>
with a preference and set the app:fragment
attribute, hence
<xml ...>
<PreferencesScreen ...>
<Preference
android:title="Title"
app:fragment="TLD.DOMAIN.PACKAGE.preferences.SUBPreferenceFragment"
app:destination="@+id/SUBPreferenceFragment" # Not supported by Schema
android:summary="Summary"/>
</PreferenceScreen>
Note : It'd be mighty handy if they allowed app:destination="@+id/SUBPreferenceFragment"
to identify the navigation destination; I simply duplicate app:destination
from the navigation graph's XML file.
From the documentation it is then possible to navigate between the PREFERENCEFramgent
s by referencing this preference.fragment
as follows
class Activity : AppCompatActivity(),
// Preferences Interface
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback
{
...
override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat, preference: Preference): Boolean
{
// Instantiate the new Fragment
val args = preference.extras
val fragment = supportFragmentManager.fragmentFactory.instantiate(
classLoader,
preference.fragment)
fragment.arguments = args
fragment.setTargetFragment(caller, 0)
// Replace the existing Fragment with the new Fragment
supportFragmentManager.beginTransaction()
.replace(R.id.FRAGMENT, fragment)
.addToBackStack(null)
.commit()
return true
}
...
}
There is however a small Snafoo ! R.id.FRAGMENT
in a normal activity represents the placeholder within the activities' view where one would swap the main fragments in an out of existence. When using Navigation R.id.FRAGMENT
maps to R.id.NAVIGATION
and the code above swaps out the entire navigation fragment with the preference. For an activity using Navigation a reformulation is necessary.
class Activity : AppCompatActivity(),
// Preferences Interface
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback
{
...
override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat, preference: Preference): Boolean {
// Retrieve the navigation controller
val navctrl = findNavController(R.id.navigation)
// Identify the Navigation Destination
val navDestination = navctrl.graph.find { target -> preference.fragment.endsWith(target.label?:"") }
// Navigate to the desired destination
navDestination?.let { target -> navctrl.navigate(target.id) }
}
...
}
While this works I am a bit dubious about the line that determines the navDestination
. If you have a better incantation for val navDestination = navctrl.graph.find { target -> preference.fragment.endsWith(target.label?:"") }
then please edit the question or leave a comment accordingly so I can update the answer.
Yes, you can use Navigation components inside Preference fragments.
I have also a main preference fragment with multiple nested fragments. For me the best way was to navigate just inside preference fragments without any activity. So I created onPreferenceClickListeners and navigate just like you would from a normal fragment.
findPreference(getString(R.string.PREF_GN_BUTTON_MAIN)).setOnPreferenceClickListener(preference5 -> {
Navigation.findNavController(requireView()).navigate(R.id.another_settings_fragment);
return true;
});
The advantage of this way is that you can use gradle plugin Safe args to navigate between destinations. So it is a little bit safer than to use it only with ids just like Carel from Activity.
I tried to override onPreferenceStartFragment
in my activity but I could not see any advantages of it. I use single Activity architecture.
© 2022 - 2024 — McMap. All rights reserved.