why optionsMenu does not show up in fragment? - android

I have an app with an Activity and multiple fragments, I want all fragments to have one default Toolbar which is managed by NavigationUI, but I want to show a Menu only for the first Fragment but the OptionsMenu doesn't show up.
this is how I set up my toolBar in MainActivity.kt:
// set Up Toolbar
val appBarConfiguration = AppBarConfiguration(navController.graph)
binding.mainToolbar.setupWithNavController(navController, appBarConfiguration)
toolbar in main_activity.xml:
<androidx.appcompat.widget.Toolbar
android:id="#+id/main_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="#style/ThemeOverlay.AppCompat.ActionBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
android:layout_marginTop="?attr/actionBarSize"/>
in the Fragment that I want an optionsMenu:
setHasOptionsMenu(true)
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.overflow_menu, menu)
}
I tried doing it with two toolbars but it doesn't seem a good practice.
how can I achieve this with one toolbar?

I was able to do it with inflateMenu:
val toolbar = activity?.findViewById<androidx.appcompat.widget.Toolbar>(R.id.main_toolbar)
toolbar!!.inflateMenu(R.menu.overflow_menu)
binding.navBtn.setOnClickListener {
navController.navigate(R.id.action_startFragment_to_secondFragment)
toolbar.menu.clear()
}
and clear it after navigation:

Related

How to display option menu without three dots android? Need to remove three dot menu and display option menu at bottom

Usual behaviour:
When we create option, we usually have three dots and when we click three dots button, option menu will be displayed. I have button on bottom too. When I click the button, option menu is displaying
My Requirement:
When we create option, how to display option menu without three dots. Because I have button on bottom and when I click the button , option menu is diplaying. But I need to remove only three dots.(hamberger menu) because my requirement is, I need to use older type where menu is present in bottom and when we click the bottom menu,it display overflow menu in androidxappcompat activity.
Update:
I used getSupportActionBar() to hide the menu. But I need to move the option menu at bottom.
needsMenuKey = appliInfo.metaData.getBoolean("com.package.name");
Log.i("MainActivity", "needsMenuKey[" + needsMenuKey + "]");
if (needsMenuKey) {
if (getSupportActionBar() != null) {
getSupportActionBar().hide();
}
You should either use NoActionBar Theme or should override onCreateOptionsMenu() and return false without calling super.onCreateOptionsMenu(). I hope one of these solutions will work for you. If yes, do mark this as answer.
So, to wrap-up the requirements:
Removing the three dots icon from the top. Instead, having a bottom button that shows the overflow options menu.
Anchor the options overflow menu to the bottom (instead of the top) when the bottom button is hit.
The system overflow options menu should be anchored to the actionBar/toolBar that hosts it; and therefore you can't show this menu at bottom unless you move this bar to the bottom too. Otherwise you need to create a customized popup menu rather than the system one.
So, the solution here is to create a customized Toolbar at the bottom of the activity:
Layout:
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:layout_constraintBottom_toBottomOf="parent">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light" />
</com.google.android.material.appbar.AppBarLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
And this requires to use a NoActionBar theme at themes.xml or styles.xml such as:
Theme.MaterialComponents.DayNight.NoActionBar or Theme.AppCompat.DayNight.NoActionBar.
And set the new supportActionBar in behavior:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolbar = findViewById<Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar)
title = ""
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
return true
}
}
This fulfills the top mentioned requirements apart from that the new supportActionBar is now at the bottom, so you probably need to add another toolbar at the top to be customized as you want.
In order to replace the three-dots icon at the bottom with a gauge icon, there are multiple answers here, and here is a one:
Add the below style:
<style name="customoverflow">
<item name="android:src">#drawable/ic_baseline_settings_24</item>
</style>
Apply it to the main theme:
<item name="android:actionOverflowButtonStyle">#style/customoverflow</item>
You can also add a paddingEnd to the toolBar to have some space between the icon and the far end of the screen:
<androidx.appcompat.widget.Toolbar
...
android:paddingEnd="16dp"
android:paddingRight="16dp"/>

Change insets for collapsing toolbar depending on its state

I have collapsing toolbar and some layout in it I want to collapse. To prevent view going under status bar, I use system insets to set margin for collapsing toolbar. I extracted AppBarLayout to separate file and included it inside CoordinatorLayout:
<com.google.android.material.appbar.AppBarLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/action_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/app_white"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
android:background="#color/colorToolbar"
android:elevation="4dp"
android:focusable="true"
android:focusableInTouchMode="true"
app:contentInsetStartWithNavigation="0dp"
app:layout_collapseMode="pin">
...
</androidx.appcompat.widget.Toolbar>
<com.google.android.material.card.MaterialCardView
android:id="#+id/bonuses_widget"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="14dp"
app:cardElevation="3dp"
app:layout_collapseMode="parallax">
...
</com.google.android.material.card.MaterialCardView>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
Margins for MaterialCardView are set from code because layout doesn't support addition. I add margins for collapsing toolbar using insets:
ViewCompat.setOnApplyWindowInsetsListener(action_bar) { _, insets ->
collapsing_toolbar.setMarginTop(insets.systemWindowInsetTop)
insets
}
This works well when collapsing toolbar is expanded, but in collapsed state toolbar goes under status bar:
I have read this question, have implemented AppBarStateChangeListener and use it like this:
action_bar.addOnOffsetChangedListener(object : AppBarStateChangeListener() {
override fun onStateChanged(appBarLayout: AppBarLayout, state: State) {
if (state == State.COLLAPSED) {
ViewCompat.setOnApplyWindowInsetsListener(collapsing_toolbar) { _, insets ->
toolbar.setMarginTop(insets.systemWindowInsetTop)
insets
}
}
if (state == State.EXPANDED) {
ViewCompat.setOnApplyWindowInsetsListener(collapsing_toolbar) { _, insets ->
toolbar.setMarginTop(0)
insets
}
}
}
})
This didn't help, as I can understand so far, status bar's insets is already handled by action bar and collapsing toolbar has nothing to handle.
I also tried to margin to toolbar at the same time with collapsing toolbar, it worked but leaded to another problem:
After all I tried to remove insets and just set android:fitsSystemWindows="true" to action bar, this fixes problem with toolbar under status bar, but status bar unexpectedly gets strange color (purple) which isn't represented in app colors.
Hope someone knows hot to handle with insets properly in this case.
You can try calling the setSupportActionBar() in your Fragment, because that works for me:
(requireActivity() as AppCompatActivity).apply {
//supportActionBar?.hide() //may need this to hide the Activity actionBar
setSupportActionBar(binding.toolbar)
}
setHasOptionsMenu(true) //don't forget this
Demo: https://youtu.be/kmnsep_V-jE
Eventually I found suitable solution:
ViewCompat.setOnApplyWindowInsetsListener(action_bar) { view, insets ->
view.updatePadding(top = insets.systemWindowInsetTop)
insets
}
There is still problem with white background under status bar (I need it to be dark as on left screenshots), but initial problem is solved.

How to make the navigation icon open a dropdown menu onclick? (Android)

So, I know it might be a very simple question however I found only very ugly solution to the problem, therefore I'm turning to you.
I have an actionbar as the following:
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize">
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/toolbar"
style="#style/Widget.AppCompat.Toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:title="#string/app_name"
app:navigationIcon="#drawable/ic_menu_black_24dp">
</com.google.android.material.appbar.MaterialToolbar>
</com.google.android.material.appbar.AppBarLayout>
I simply couldn't find any normal way causing the sandwich icon to open a small dropdown menu of options once being clicked.
Thanks to the helpers!
you need to add menu code for that like this in activity class file,
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Get menu inflater.
MenuInflater menuInflater = getMenuInflater();
// Use app bar layout menu to inflate the tool bar.
menuInflater.inflate(R.menu.your_menu_name, menu);
return super.onCreateOptionsMenu(menu);
}

Hide/show arrow/menu on toolbar

So, i have Activity with FrameLayout, code of activity layout
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_main"/>
and when i'm going to differents fragment i need to change toolbar.
I need to set different text, show back arrow, remove back arrow, and show/remove three dots in right corner for menu.
I have next code in Activity
#Override
public void onCreate(Bundle savedInstanceState) {
...
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
...
}
and next methods in my class
public void setTextTabBar(String title) {
getSupportActionBar().show();
getSupportActionBar().setTitle(title);
}
public void setTabBarFragment() {
getSupportActionBar().show();
getSupportActionBar().setTitle(getString(R.string.about_app_title));
toolbar.setNavigationIcon(android.support.v7.appcompat.R.drawable.abc_ic_ab_back_material);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
setFragment(fragmentMain);
}
});
}
Is this right way? I'm coding to android 8+.
Also i need to add menu, and remove back arrow, how to implement this?
I don't think so, assuming your fragment transaction is replacing the <include layout="#layout/content_main"/> part of your code. According to this post: ActionBar (Support) with Fragment (support)
You need to extend each fragment so they can have their own action bars.
This makes sense as fragments are supposed to be modular in nature and only call back to the host activity when you implement special functions, callbacks, or listeners to do so.
As far as your back arrows go, you will need the code lines: getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true); to enable and set the back button. And just change the booleans to false if removing the back arrow.

Toolbar - add the up button

I am trying to use the Toolbar instead of the ActionBar, but I can't figure out how to add the up button to return to the previous activity.
I couldn't find any method that could relate to it.
How do I add the up button?
I guess what you are looking for is something like this:
Toolbar toolbar = (Toolbar) findViewById(R.id.app_bar_detail);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Or in case of using in Fragment:
Toolbar toolbar = (Toolbar) view.findViewById(R.id.app_bar_detail);
((ActionBarActivity) getActivity()).setSupportActionBar(toolbar);
((ActionBarActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
This will show up your Action Bar inside of your toolbar, but don't worry everything will fit together well. The last you have to do if you dont want any shadow under your action bar or any background of it is change your theme in vaules/styles.xml.
<style name="AppThmeme.Base" parent="Theme.AppCompat.NoActionBar">
If you want to do this in XML, you can use...
<android.support.v7.widget.Toolbar
app:navigationIcon="?homeAsUpIndicator"
...
If you're wondering why clicking on up button doesn't work with fragments, you need to set up a navigation listener as well, not sure why Google hasn't enabled it by default:
protected fun setupToolbar(toolbar: Toolbar) {
(activity as AppCompatActivity).run {
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
toolbar.setNavigationOnClickListener { onBackPressed() }
}
}
In case when previous activity is always same for a given activity then up/back button can be achieved with the help of parentActivityName attribute. It can be mentioned in AndroidManifest.xml file as shown below:
<activity android:name=".DetailActivity" android:parentActivityName=".MainActivity">
<meta-data android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity" />
</activity>
Let's say DetailActivity was opened from MainActivity. So when you are on DetailActivity then tool bar will automatically show a left pointing arrow (Refer screenshot):
When we click on left pointing arrow then MainActivity gets displayed.
Calling getSupportActionBar().setHomeButtonEnabled(true); should still work I think, as long as you have already called setSupportActionBar(toolbar);
You can add your own 'up' button in toolbar, after all it is just a ViewGroup.
You can customize toolbar as much as you want, in your toolbar.xml, or wherever you have defined android.support.v7.widget.Toolbar in your layout add your 'up' button like given below :
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/toolbar"
android:minHeight="?attr/actionBarSize"
android:layout_height="?attr/actionBarSize"
android:background="#drawable/color_toolbar"
android:layout_width="match_parent">
<ImageButton
android:id="#+id/upButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="uphandler"
android:src="#drawable/backbutton"
android:layout_gravity="end"/>
</android.support.v7.widget.Toolbar>
Now, define uphandler function in your activity to listen to this up button :
public void uphandler(View v){
this.finish(); // This will kill current activity, and if previous activity is still opened in background, it will come in front.
}
You have to add these line back button show automatically
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
on back, button click automatically back to activity
#Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
if you are using navigation component, then adding up button in fragment would be like this:
in your fragment.xml
<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=".presentation.recipeitem.RecipeDetailsFragment">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_constraintTop_toTopOf="parent"
android:elevation="4dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
/>
.
.
then in your fragment you would do this
inside onViewCreated(..)
val navController = findNavController()
val appBarConfiguration = AppBarConfiguration(navController.graph)
viewBinding.toolbar.setupWithNavController(navController, appBarConfiguration)
if you need to add title then use this in onResume
viewBinding.toolbar.title = "my title"
if you are using newer version of android studio:
first declare toolbar of androidx not android
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorAccent"
app:popupTheme="#style/Theme.Sunshine.PopupOverlay" />
second, get a reference to the toolbar in Activity.java and use following code;
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar ab= getSupportActionBar();
ab.setDisplayHomeAsUpEnabled(true);

Categories

Resources