Al Hennessey
Al Hennessey

Reputation: 2445

Using Toolbar with Fragments

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?

Upvotes: 48

Views: 112450

Answers (6)

amsuredev
amsuredev

Reputation: 51

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)
        }
    }

Upvotes: 1

Faisal Naseer
Faisal Naseer

Reputation: 4248

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
   }
});

Upvotes: 54

Linh
Linh

Reputation: 60913

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

Upvotes: 22

H.T
H.T

Reputation: 161

You can add toolbar in Fragments using this

 ((YOUR_ACTIVITY) getActivity()).getDelegate().setSupportActionBar(toolbar);

Upvotes: 2

vinitius
vinitius

Reputation: 3274

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);

Upvotes: 88

muruthi
muruthi

Reputation: 345

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

((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);

Upvotes: 9

Related Questions