47

I am trying to create a viewpager that swipes through 3 different fragments each with a different toolbar. I have implemented the new toolbar in an activity before and got it to work however I am trying to get it to work with fragments

Here is the fragment code

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    // Inflate the layout resource that'll be returned
    View rootView = inflater.inflate(R.layout.fragment_home, container, false);


    mToolbar = (Toolbar) rootView.findViewById(R.id.toolbar_home);
    if (mToolbar != null) {
        setSupportActionBar(mToolbar);
    }
    mToolbar.setTitle(null);

    return rootView;
}

I am extending my fragment with Fragment, however I am getting the error

Cannot resolve method setSupportActionBar

I am not sure how to resolve this, if I remove the setSupportActionBar code will it stop working with certain devices?

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Al Hennessey
  • 2,395
  • 8
  • 39
  • 63
  • Is there an issue with having it in your activity layout and setting it in your activity? – tachyonflux Mar 12 '15 at 21:53
  • 1
    each toolbar for each viewpager will have a different color and different menus, so i thought it would be better to control them with the fragments – Al Hennessey Mar 12 '15 at 21:59
  • Hang on, isn't the whole point in this scenario *not* to set the `ToolBar` as `ActionBar`? Since your intention is for every fragment to have its own `ToolBar` (which swipes along with the other content of the fragment), we're talking about the ['standalone'](http://android-developers.blogspot.nl/2014/10/appcompat-v21-material-design-for-pre.html) (scroll down to the 'standalone' section) usage of the widget. – MH. Mar 12 '15 at 22:06
  • 1
    The menu part is already supported with different menu xmls and attaching via `onCreateOptionsMenu`. The color part can be done within the `onAttach` using something like http://stackoverflow.com/questions/25081706/how-to-change-programmatically-background-color-of-action-bar-items – tachyonflux Mar 12 '15 at 22:13

6 Answers6

88

Fragments don't have such method setSupportActionBar(). ActionBar is a property of Activity, so to set your toolbar as the actionBar, your activity should extend from ActionBarActivity and then you can call in your Fragment:

 ((ActionBarActivity)getActivity()).setSupportActionBar(mToolbar);

UPDATE

If you're using AppCompatActivity :

 ((AppCompatActivity)getActivity()).setSupportActionBar(mToolbar);
vinitius
  • 3,212
  • 2
  • 17
  • 22
  • 1
    In my case this does not replace the actionbar of the Mainactivity but it gives the Toolbar a title like in the Mainactivity. – Roel Sep 18 '15 at 13:35
  • 2
    @vinitius Hey in your above answer you forgot to write "()" after getActivity. so please add this so other people will not get confuse. – Ram Mansawala Oct 28 '15 at 10:47
  • Shifting SupportActionBar from Activity's toolbar to Fragments toolbar may loose Support for Activity toolbar. what if you need to update the Activity toolbar once inside Fragment with shifted SupportActionBar ? :). – Faisal Naseer Sep 26 '17 at 06:42
53

I have seen a lot of answers mentioning to setSupportActionBar for toolbar inside Fragment but this approach may go wrong if you are having a a toolbar in Activity and a separate Toolbar in Fragment.

  1. As you shift setSupportActionBar from Activity's Toolbar to Fragment's toolbar, You may face duplication of MenuItem even you try to override using setHasOptionsMenu(true).
  2. Secondly If you want to update Activity's Toolbar you see your changes are not reflected because of setSupportActionBar inside your Fragment.

So in order to avoid this I recommend to use toolbar methods like this inside fragment to inflate menu and use

 toolbar = (Toolbar) view.findViewById(R.id.toolbar_frag);
    toolbar.inflateMenu(R.menu.frag_menu_items);
    Menu menu = toolbar.getMenu();

and use Toolbar.OnMenuItemClickListener interface to receive with menuItems click events.

Edit (Section Copied from MrEngineer13 answer)

and if you are worried about the back button you can set it like this

toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_action_back));
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
       //What to do on back clicked
   }
});
Faisal Naseer
  • 4,110
  • 1
  • 37
  • 55
  • Hi Faisal Naseer can you explain it in detail becoz i m facing the same problem that you describe. – Ness Tyagi Sep 11 '17 at 09:17
  • sure whats the issue at your end have you tried the above approach. – Faisal Naseer Sep 22 '17 at 11:25
  • 1
    I have resolved the issue using your code by RND thanks for your feedback. Actually i have only one Activity and rest of all fragment in my app. So updating the toolbar with option menu in each fragment occur the issue. But with your code its working fine Thankyou. – Ness Tyagi Sep 25 '17 at 04:38
22

Base on @Faisal Naseer answer. Here is the full example (with few notes) for using custom Toolbar with navigation and menu in Fragment

fragment_home.xml

<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"">

    ...
    <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar_home"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:title="Home" /> 

</androidx.constraintlayout.widget.ConstraintLayout>

HomeFragment.kt

class HomeFragment : BaseFragment() {

    override fun onCreate(savedInstanceState: Bundle?) {
        // setHasOptionsMenu(true): don't need this anymore
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_home, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        toolbar_home.setNavigationIcon(R.drawable.ic_back) // need to set the icon here to have a navigation icon. You can simple create an vector image by "Vector Asset" and using here
        toolbar_home.setNavigationOnClickListener {
            // do something when click navigation
        }

        toolbar_home.inflateMenu(R.menu.menu_home)
        toolbar_home.setOnMenuItemClickListener {
            when (it.itemId) {
                R.id.action_add -> {
                    // do something
                    true
                }
                R.id.action_update -> {
                    // do something
                    true
                }
                else -> {
                    super.onOptionsItemSelected(it)
                }
            }
        }
    }
}

menu_home.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/action_add"
        android:title="@string/add_device"
        app:showAsAction="never" />

    <item
        android:id="@+id/action_update_room"
        android:title="@string/update_room"
        app:showAsAction="never" />

</menu>

Hope it help

enter image description here

Linh
  • 57,942
  • 23
  • 262
  • 279
  • Hi, the inflate menu working very well but setOnMenuItemClickListener doesn't work Need help. – a-rohim Oct 10 '19 at 10:51
  • even for single menu it shows overflow menu. I dont want overflow menu, what can done to achieve that? – akshay May 29 '20 at 04:29
  • how about if I don't wanna back arrow, how can I hide it?, I need only three dots – iamkdblue Jul 06 '20 at 12:52
  • @Phan, Where is BaseFragment can you provide me that also? Because `toolbar_home` is not finding here in this example. – AndyBoy Sep 12 '20 at 18:34
9

With the new AppCompatActivity you should call it instead of ActionBarActivity:

((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);
muruthi
  • 345
  • 4
  • 5
2

You can add toolbar in Fragments using this

 ((YOUR_ACTIVITY) getActivity()).getDelegate().setSupportActionBar(toolbar);
H.T
  • 161
  • 7
1

I use Kotlin. In my case Activity is a child class of AppCompatActivity and theme of activity is inherited from Theme.MaterialComponents.DayNight.NoActionBar

So my Activity doesn't have action bar, but my Fragment do.

I will show you how to use toolbar with defined menu as a SupportActionBar in fragment

This is my Toolbar

<com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appBarLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:fitsSystemWindows="true"
            app:navigationContentDescription="Back to the previous question"
            android:background="?attr/colorPrimary"
            tools:title="@string/posts" />

This is my Fragment's methods:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        (context as AppCompatActivity).setSupportActionBar(_bind?.toolbar)
        setHasOptionsMenu(true)
}
    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        super.onCreateOptionsMenu(menu, inflater)
        inflater.inflate(R.menu.toolbar_menu_post_list, menu)
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return when(item.itemId)
        {
            R.id.add -> {
                val post = Post()
                postListViewModel.addPost(post)
                callbacks?.onItemSelected(post.id)
                return true
            }
            else -> super.onOptionsItemSelected(item)
        }
    }

amsuredev
  • 21
  • 1