Coordinator Layout with Toolbar in Fragments or Activity
Asked Answered
S

4

97

With the new design library there are several new layouts that change a lot how the toolbar can behave if the developer so wishes. Since different fragments have different behaviors and objectives, for example a gallery fragment with a collapsing toolbar showing an important photo, or a fragment without a scrollview that just doesn't need the appbarlayout for hiding the toolbar, having a single toolbar in the activity can prove difficult.

So with this, should I move the toolbar to each fragment? If so, I have to set the supportActionBar each time I show a fragment and also have a reference of the activity in the fragment which nullifies the independent nature of fragments. If I leave the toolbar in the Activity alone, I have to have multiple layouts defined for each type of behavior in each fragment. What would be the best approach?

Stint answered 9/6, 2015 at 18:18 Comment(2)
for my current project I have decided to stick with the toolbar in the Activity and do the proper animations when required. But it is a bit convoluted. I tried using toolbar in each fragment and it works fine, but animating the toolbar between fragment transitions is more difficult and I don't even know if it is possible because I don't have much experience with fragment transitions animations.Stint
any updates or better solutions to this now?Gearing
A
57

As for me it sounds too weird to have appbar and toolbar in each fragment. So I've chosen to have single appbar with toolbar in activity.

To solve that issue with CoordinatorLayout you will have to set different behaviour of your FrameLayout (or any other Layout) that supposed to hold fragments from each fragment that you want to override default behaviour.

Lets assume, that your default behaviour is app:layout_behavior="@string/appbar_scrolling_view_behavior"

Then in your fragment_activity_layout.xml you may have something like that:

<android.support.design.widget.CoordinatorLayout
    android:id="@+id/coordinator"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.v7.widget.Toolbar
            android:id="@+id/dashboard_toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/AppTheme.Toolbar"
            app:layout_scrollFlags="scroll|enterAlways"/>
    </android.support.design.widget.AppBarLayout>

    <FrameLayout
        android:id="@+id/dashboard_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>

And in each fragment you wish not to implement app:layout_behavior="@string/appbar_scrolling_view_behavior" you will have to override onAttach and onDetach methods that will change behaviour of your FrameLayout:

CoordinatorLayout.Behavior behavior;

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);

    if(behavior != null)
        return;

    FrameLayout layout =(FrameLayout) getActivity().findViewById(R.id.dashboard_content);
    CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) layout.getLayoutParams();

    behavior = params.getBehavior();
    params.setBehavior(null);

}

@Override
public void onDetach() {
    super.onDetach();
    if(behavior == null)
        return;

    FrameLayout layout =(FrameLayout) getActivity().findViewById(R.id.dashboard_content);
    CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) layout.getLayoutParams();

    params.setBehavior(behavior);

    layout.setLayoutParams(params);

    behavior = null;
}

After that CoordinatorLayout won't collapse appbar, etc. and will allow fragment layouts to be full-height.

Anesthesiologist answered 16/8, 2015 at 13:48 Comment(6)
Nice one, will have to try this and see if it simplifies things. Thanks.Stint
If you'll find something simpler — let me know. I think it is possible to change coordinator behaviour at any moment during fragments' life cycle (e.g. you normally have a recycler with some stuff but in rare cases it might be empty and u'll know that only after Loader's onLoadFinished, it's possible you'd like to show centred image notifying that nothing is here, just like in Inbox App), but I didn't try that yet. Maybe later today.Earphone
Ok, that works pretty well. I cr8ted a helper that takes care for enabling/disabling coordinator when appropriate, so I just call enableCoordinator(Activity activity) / disableCoordinator(Activity activity) from fragments.Earphone
Where is your helper, @КлаусШварц? When do you call it?Machute
@Machute In the FragmentEarphone
while using bottombar with many buttons and different fragment with different TabLayout we have to move all Appbar with toolbar to fragment instead of activity !!Hauger
F
8

Here's my solution

<!-- Put your fragment inside a Framelayout and set the behavior for this FrameLayout -->
<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <!-- Your fragment -->
    <include layout="@layout/content_main" />

</FrameLayout>

<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:layout_scrollFlags="scroll|enterAlways"
        app:popupTheme="@style/AppTheme.PopupOverlay" />

</android.support.design.widget.AppBarLayout>

Flit answered 8/10, 2015 at 17:9 Comment(0)
S
1

This is a realy good question: should Toolbars that need to act like an ActionBar be kept in a Activity or a Fragment? Having searched around different questions and documentation, I couldn't find a solution that covers all cases. It therefore really depends on your situation wich way to go.

Case 1: Toolbar must be ActionBar replacement

If the Toolbar has to behave like a normal ActionBar (or if max 1 fragment is shown from time to time), I think the best/simplest way is to use traditional Activities with there own Toolbar and put your Fragment in there. This way you don't have to worry about when which Toolbar must be shown.

Changing the ActionBar (-behaviour) from Fragments is also possible, but I would not recommend it, since that forces you to keep track which Fragment changed the ActionBar when. I don't even know if setting the ActionBar can be done multiple times.

Case 2: Each Fragment should have its own (part of) Toolbar

You could also choose to put different stand alone Toolbars in different Fragments, with their own actions. This way you could display different Fragments next to each other - each with their own actions in their Toolbar - and suggest that it is 1 Toolbar (maybe like the Gmail-app, although I am unsure). This however means that you would have to inflate those Toolbars yourself, but it must not be very difficult.

I hope this will help making a choice.

(Sorry if I made any (language-)mistakes)

Swaddle answered 15/6, 2015 at 19:1 Comment(1)
sorry but this doesn't really answer the problems relative with the new design library. Sure having the toolbar as actionbar is the objective, but having multiple coordinator layouts for different types of toolbars can be tricky. What I found is that it is possible to animate the toolbar as needed. I still need to test it better but it seems there is good resultsStint
S
1

That's what the navigation documentation says:

Adding the top app bar to your activity works well when the app bar’s layout is similar for each destination in your app. If, however, your top app bar changes substantially across destinations, then consider removing the top app bar from your activity and defining it in each destination fragment, instead.

Actually it's very easy to setup a Toolbar using NavigationUI, and this solution doesn't require the Fragment to have any knowledge about its parent. For example:

<!-- my_fragment.xml -->
<androidx.constraintlayout.widget.ConstraintLayout ...>

  <com.google.android.material.appbar.MaterialToolbar
    android:id="@+id/toolbar"
    ... />

</androidx.constraintlayout.widget.ConstraintLayout>
class MyFragment : Fragment() {
  ...

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

    val navController = findNavController()
    binding.toolbar.setupWithNavController(navController)
  }
}

You can find the full GitHub example here. There's also a relative question that might be interested Is setSupportActionbar required anymore?

Sigvard answered 12/12, 2020 at 12:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.