As promised. This is how I did it. I'm posting because an internet search dindn't find anyone already address the question and since I figured it out I thought it might be helpful to others in the future.
Also, I think its probably obvious to more seasoned Android Developers but I'm new so I'm unsure when things work.
So I'm already using Navigation from a mainNavHostFragment located in my single activity's MainActivity.Java file.
And what you have to type to use "Navigation" is so much nicer than using "Fragment Transactions" and "Fragment Factories" so I figured this out so that I could keep using Navigation and avoid using the o.g. Fragment manipulation techniques.
Now when users click the "Settings" icon I provide them, that first mainNavHostFragment navigates the user to a HolderOfSettingsFragment.java class.
In that HolderOfSettingsFragment.java class I have a second NavHostFragment named settingsNavHostFragment which is ...
- initialized using
getChildFragmentManager instead of getSupportFragmentManager
- and initialized to the
androidx.fragment.app.FragmentContainerView in its layout.
And in the usual fashion I have a settingsNavController gotten from the settingsNavHostFragment.
That FragmentContainerView uses a navGraph named sub_navigation_from_settings which is different than the one my MainActivity uses. The starting fragment in sub_navigation_from_settings is my root_preferences and its got a [navigation] action to my SubSettingsExampleFragment.
According to the documentation at https://developer.android.com/develop/ui/views/components/settings all you have to do to make a "link" from the root preference screen to an additional screen is list a <Preference/> tag with an app:title entry that will match the <PreferenceCategory> in the "linked" screen as well as app:fragment indicating the fragment class to jump to.
The Preference Fragments themselves are actually pretty boring. They are literally just a class that extends PreferenceFragmentCompat which implements onCreatePreferences whose single action is to apply setPreferencesFromResource to appropriate preference resources located in your XML directory.
According to the same documentation in order to respond to "link" clicks in the root_prefernces you need to implement PreferenceFragmentCompat.OnPreferenceStartFragmentCallback. The documentation says to do this in the Activity but I did it in HolderOfSettingsFragment and it works just fine.
Further, implementing the PreferenceFragmentCompat.OnPreferenceStartFragmentCallback interface means implementing the onPreferenceStartFragment which is called with both a caller and 'pref`. So we do that.
To let the settingsNavHostFragment handle things we just check if pref.getTitle matches a given title and if it does we use the settingsNavController to navigate to the appropriate "Preference Fragment" using the id of the actions in the sub_navigation_from_settings graph.
Its working just fine for me. Yay!
Its possible that down the line this won't work because of something I don't know causing a conflict but until then I'm glad it works.
I hope this helps someone other than me.
Here is all the code if you want to look at that directly.
Here is the holder java class:
package com.example.app;
import ...
import com.example.app.databinding.FragmentSettingsHolderBinding;
public class HolderOfSettingsFragment extends Fragment implements
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
public static final String TAG = "HolderOfSettingsFragment-";
FragmentSettingsHolderBinding bindingOfThis;
NavController settingsNavController;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
bindingOfThis = FragmentSettingsHolderBinding.inflate(inflater, container, false);
return bindingOfThis.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
NavHostFragment settingsNavHostFragment = (NavHostFragment) getChildFragmentManager().findFragmentById(R.id.settingsHolderFragContainer);
settingsNavController = settingsNavHostFragment.getNavController();
bindingOfThis.imgReturnIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
((AppCompatActivity) getActivity()).onBackPressed();
}
});
}
@Override
public boolean onPreferenceStartFragment(@NonNull PreferenceFragmentCompat caller, @NonNull Preference pref) {
String stringToCompare = (String) pref.getTitle();
if ( stringToCompare.equalsIgnoreCase("Other Settings") ) {
settingsNavController.navigate(R.id.action_settingsFragment_to_subSettingsExampleFragment);
}
return true;
}
@Override
public void onDestroy() {
super.onDestroy();
bindingOfThis = null;
}
}
It has the following layout:
Note that the Android Studio Editor will not render this layout and I believe that's because the Settings resources are pure-er XML stored in the XML resource directory.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HolderOfSettingsFragment">
<ImageView
android:id="@+id/imgReturnIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:src="?attr/actionModeCloseDrawable"
app:layout_constraintEnd_toStartOf="@+id/txtSettingsTitle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/txtSettingsTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="12dp"
android:text="Settings"
android:textAppearance="@style/TextAppearance.AppCompat.Widget.ActionMode.Title"
app:layout_constraintBottom_toBottomOf="@+id/imgReturnIcon"
app:layout_constraintStart_toEndOf="@+id/imgReturnIcon"
app:layout_constraintTop_toTopOf="parent" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/settingsHolderFragContainer"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toBottomOf="@id/imgReturnIcon"
android:layout_marginTop="40dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="@navigation/sub_navigation_from_settings"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
Here is the second NavGraph:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/sub_navigation_from_settings"
app:startDestination="@id/settingsFragment">
<fragment
android:id="@+id/settingsFragment"
android:name="com.example.app.SettingsFragment"
android:label="SettingsFragment" >
<action
android:id="@+id/action_settingsFragment_to_subSettingsExampleFragment"
app:destination="@id/subSettingsExampleFragment" />
</fragment>
<fragment
android:id="@+id/subSettingsExampleFragment"
android:name="com.example.app.SubSettingsExampleFragment"
android:label="SubSettingsExampleFragment" />
</navigation>
Here is the root settings XML:
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory app:title="Current User">
<SwitchPreferenceCompat
app:key="current_user_hide_tb_labels"
app:title="Hide labels underneath Toolbar Icons?"
app:defaultValue="false"/>
</PreferenceCategory>
<Preference
app:title="Other Settings"
app:summary="Other Settings Example"
app:fragment="com.example.app.SubSettingsExampleFragment" />
And finally the separate example settings screen's xml:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory app:title="Other Settings">
<SwitchPreferenceCompat
app:key="do_you_like"
app:title="Do you like me?"
app:defaultValue="false"/>
</PreferenceCategory>
</PreferenceScreen>