I'm trying to follow this: https://developer.android.com/guide/navigation/navigation-ui along with a review of https://codelabs.developers.google.com/codelabs/android-navigation/#8 (although the second link is in Kotlin and I'm coding in Javascript) to implement an App in Android with navigation drawer on the left and a settings button (preferences) on the top right.
I'm using the NavigationUI with fragments for each option from the drawer and the settings.
My problem is that my settings fragment is not appearing. I think I'm nearly there, but despite reviewing several articles and questions cannot get it to work.
This code allows me to switch fragment from the nav drawer:
@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);
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow)
.setDrawerLayout(drawer)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
//NavigationUI.setupWithNavController(toolbar, navController, mAppBarConfiguration);
}
If I switch the commented code on the last two lines (so I execute the last line but not second to last), to match the guide then the switching of fragment fails.
My code to handle the Settings menu is:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
return NavigationUI.onNavDestinationSelected(item, navController)
|| super.onOptionsItemSelected(item);
/*
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
// TODO: Do something to accept settings
View contextView = findViewById(R.id.nav_host_fragment); // Apparently any layout can be used
Snackbar.make(contextView, "Settings", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
//changeFragment(new SettingsFragment());
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.nav_host_fragment, new SettingsFragment(), "nh")
.addToBackStack("nh")
.commit();
return true;
}
return super.onOptionsItemSelected(item);
*/
}
The active portion matches the guide above, is getting called (proved by setting a breakpoint) but doing nothing.
If I alternatively switch this for the commented out code instead, then my settings fragment does appear but overlays the current fragment. I understand from another answer that this is because I am using two different methods to handle fragment visibility, which makes sense and is why I am trying to get my settings fragment to be handled by the NavigationUI framework.
I feel that it must be quite simple to cure, but having read and re-read the guide (and lots of answers cannot make it work)
And this is the Code. As you see I've an action in SettingsFragment:
<fragment
android:id="@+id/settingsFragment"
android:name="packageName.SettingsFragment"
android:label="Settings Fragment">
<action
android:id="@+id/actionSettingsToPassword"
app:destination="@id/passwordDialogFragment"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit" />
And this is my bottomNavigationMenu's XML:
<item
android:id="@+id/settingsFragment"
android:icon="@drawable/ic_settings"
android:title="Settings" />
Remember that the ID in the Navigation & Menu should be the same. As you see in the codes, the ID of "Settings Fragment" is the same:
android:id="@+id/settingsFragment"
I don't know if you know how to add preferences.xml in your resources. Just for sure I write it too:
Right Click on "res" New > Android Resource Directory
In the Resource Type field, pickup XML. Now you gonna have xml folder under "res". Again:
Right Click on "xml" New > XML Recourse File
Now, Here is my "preferences.xml":
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="Weather Location">
<SwitchPreference
android:defaultValue="true"
android:disableDependentsState="true"
android:key="USE_DEVICE_LOCATION"
android:summary="Allow The App To Get Your Location"
android:title="Use Device Location" />
<EditTextPreference
android:defaultValue="Tehran"
android:dependency="USE_DEVICE_LOCATION"
android:key="CUSTOM_LOCATION"
android:summary="The Location For Which The Weather Is Displayed"
android:title="Location" />
</PreferenceCategory>
<PreferenceCategory android:title="Units">
<ListPreference
android:defaultValue="METRIC"
android:entries="@array/unitSystemEntries"
android:key="UNIT_SYSTEM"
android:summary="%s"
android:title="Unit System"
android:entryValues="@array/unitSystemValues"/>
</PreferenceCategory>
</PreferenceScreen>
Then create a "Kotlin" or "Java" class and set the XML to your class like this (depend on which language are you writing):
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.preferences)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
(activity as? AppCompatActivity)?.supportActionBar?.title = "Settings"
(activity as? AppCompatActivity)?.supportActionBar?.subtitle = null
}
}
And here is my Application Class:
class ForecastApplication : Application(){
override fun onCreate() {
super.onCreate()
PreferenceManager.setDefaultValues(this, R.xml.preferences, false)
}
}
and in your application's Manifest, inside the application tag, define the Application class you already created.
android:name=".ForecastApplication"
I hope this is what you needed.