4

This is whatsapp when you are not scrolling upwards. The toolbar is showing and so is the tablayout underneath it.

SCREENSHOT1:

whatsapp1

This is whatsapp once you are scroll it up. You can see that the toolbar is hidden.

SCREENSHOT2:

whatspp2

There is a guide to show you how to create this effect. I have followed it and got this effect to work within my app.

https://mzgreen.github.io/2015/06/23/How-to-hideshow-Toolbar-when-list-is-scrolling(part3)/

link from guide

My question is about showing a snackbar when you have the toolbar showing as in SCREENSHOT1. When I try to show a snackbar when the toolbar is showing, it actually shows below the screen so that it is not visible to the user. Only if the user scrolls up and hides the toolbar will the snackbar be visible.

The xml I used for my app is similar to the one used in the guide https://github.com/mzgreen/HideOnScrollExample/blob/master/app/src/main/res/layout/activity_part_three.xml. I have copied and pasted the code as per the link below:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
                                                 xmlns:app="http://schemas.android.com/apk/res-auto"
                                                 android:id="@+id/coordinatorLayout"
                                                 android:layout_width="match_parent"
                                                 android:layout_height="match_parent">
    <android.support.design.widget.AppBarLayout
            android:id="@+id/appBarLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

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

        <android.support.design.widget.TabLayout
                android:id="@+id/tabLayout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:tabTextColor="@android:color/white"
                app:tabSelectedTextColor="@android:color/white"
                app:tabIndicatorColor="@android:color/white"
                app:tabIndicatorHeight="6dp"/>
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

    <android.support.design.widget.FloatingActionButton
            android:id="@+id/fabButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="end|bottom"
            android:layout_margin="@dimen/fab_margin"
            android:src="@drawable/ic_favorite_outline_white_24dp"
            app:borderWidth="0dp"
            app:layout_behavior="pl.michalz.hideonscrollexample.ScrollingFABBehavior"/>

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

Does anyone know how I can show the snackbar when the toolbar is visible?

EDIT:

Because the layout scheme contains tablayouts and each of these tablayouts displays a fragment, I'm trying to show the snackbar per fragment and not at the activity level. I'm actually starting to think that this might not be possible to show the snackbars per fragment and this might actually needs to be done through tying listeners from each of those 3 fragments to the main activity and then the snackbar must just be displayed in the main activity instead.

This is the xml of one of my fragments:

<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/snackbarPosition">

    <android.support.v4.widget.SwipeRefreshLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/swipeContainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

            <android.support.v7.widget.RecyclerView
                android:id="@+id/my_recycler_view"
                android:layout_below="@+id/join"
                android:scrollbars="vertical"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
            </android.support.v7.widget.RecyclerView>

    </RelativeLayout>

    </android.support.v4.widget.SwipeRefreshLayout>

</android.support.design.widget.CoordinatorLayout>
Simon
  • 19,658
  • 27
  • 149
  • 217

3 Answers3

2

Try setting your ViewPager’s height to wrap_content.

The CoordinatorLayout should keep its dimensions in check without using match_parent.

Additionally, make sure you’re passing a descendant view of your CoordinatorLayout to Snackbar.make.

Update based on the comments:

The Snackbar will walk up the view hierarchy starting from the view you give it and attach itself to the first CoordinatorLayout it finds or the window decor’s content view if it finds none.

If you’re nesting CoordinatorLayouts within fragments, you need to make sure that the child CoordinatorLayouts don’t overflow their containers, which might be tricky.

In my opinion it might be easier to remove the CoordinatorLayouts in the fragments, and give Snackbar.make a view from your fragment instead. It will happily walk up the hierarchy (even out of the fragments) to reach the CoordinatorLayout in your activity.

If you do that, the callbacks will work as usual, but make sure to mark any callbacks you use as static to avoid leaking your fragments in case the Snackbar stays on screen after your fragment is supposed to be gone.

This can happen because the Snackbar will hold a reference to your callback, which in turn can hold a reference to your fragment. If you need a reference to the fragment or a context, use a weak reference.

Leo Nikkilä
  • 1,547
  • 18
  • 29
  • Changing the viewpager height to wrap_content does not fix the issue unfort. Also the viewpager contains the fragments and each fragment has coordinatorlayout views. Maybe I was not clear in my question and will edit it shortly but I'm trying to get the snackbars to show inside each fragment itself and not in the activity. Not sure if that is a possibility and maybe the simpliest way to solve this issue is actually to make one snackbar for the activity and if the tie listeners from the fragments to activities so that the activity will show the snackbar when called by the fragment. – Simon Dec 30 '15 at 17:55
  • I’ve updated the answer with a section on how Snackbars attach in fragments. – Leo Nikkilä Dec 30 '15 at 18:09
  • Sorry - I have a question on your answer - the snackbars are triggered within each fragment. Lets say the fragment does network calls and one of them fails. The snackbar is suppose to say "No internet" and with my current setup, it will attach itself to the coordinatorlayout called "@+id/snackbarPosition". I need it to walk up to the activity's coordinatorlayout, which is called "@+id/coordinatorLayout". Is that possible? Should i just pass a reference from my activity to fragment for "@+id/coordinatorLayout" and use that reference in my snackbar.make? – Simon Dec 30 '15 at 18:29
  • You have basically two options to achieve that: either remove the inner CoordinatorLayouts and pass Snackbar.make any view from your layout, or keep the inner layouts and pass Snackbar.make a view from above your fragment’s root view (i.e. a view from your activity.) Referencing the outer layout in the fragment is a feasible way to do the latter, but I would see if I can eliminate nested CoordinatorLayouts altogether since they’re likely to cause more troubles like this further on. – Leo Nikkilä Dec 30 '15 at 18:50
  • Thanks - your second option is the right answer actually. I just tested it and it works. I will also be posting a solution of how I solved this. +1 and thanks for your help. – Simon Dec 30 '15 at 18:54
2

Pretty easy. Just use the viewPager as the view and you're done. It looks something like this:

Snackbar snackbar = Snackbar.make(findViewById(R.id.viewPager), "Your Message", Snackbar.LENGTH_LONG);
    snackbar.getView().setBackgroundColor(Color.parseColor("#00b8ba"));
    snackbar.show();

Make sure you pass the findViewById(R.id.viewPager) as the view.

By the way the viewPager is defined as this:

<android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

For different fragments use this (first fragment):

Snackbar snackbar = Snackbar.make(getView(), "First", Snackbar.LENGTH_LONG);
        snackbar.getView().setBackgroundColor(Color.parseColor("#00b8ba"));
        snackbar.show();

second fragment:

Snackbar snackbar = Snackbar.make(getView(), "Second", Snackbar.LENGTH_LONG);
        snackbar.getView().setBackgroundColor(Color.parseColor("#00b8ba"));
        snackbar.show();
Christoph Möbius
  • 1,352
  • 1
  • 12
  • 18
Nilesh Singh
  • 1,750
  • 1
  • 18
  • 30
  • Hi, I don't think I was clear in my initial question but I'm trying to show the snackbar per fragment and not at the activity level. Your answer would work if i was doing this at the activity level but can u think of something that would work at fragment level? – Simon Dec 30 '15 at 17:59
  • Sorry - I have a question on your answer - the snackbars are triggered within each fragment. Lets say the fragment does network calls and one of them fails. The snackbar is suppose to say "No internet" and with my current setup, it will attach itself to the coordinatorlayout called "@+id/snackbarPosition". I need it to walk up to the activity's coordinatorlayout, which is called "@+id/coordinatorLayout". Is that possible as i need the snackbar to display in my activity and not my fragment. – Simon Dec 30 '15 at 18:43
  • Sorry but how can you show the response to a fragment call in another activity? You may need to save the data and when that particular actitivity opens and detects that an error occurred, it will show the snackbar attached to the "@+id/coordinatorLayout", and if everything goes right (or the data persisted and received in the activity is null) nothing happens. – Nilesh Singh Dec 30 '15 at 18:48
  • it is not in another activity - the fragment is nested within the activity and that activity holds the coordinatorlayout "@+id/coordinatorLayout". When the activity is displayed, the fragment is displayed with it. Currently I'm passing the snackbar to coordinatorlayout sitting within my fragment which is why it is not displaying until you scroll up. I just managed to solve this issue by passing a reference from my activity to my fragment for the activity coordinatorlayout and it works fine now. I will post a solution shortly. – Simon Dec 30 '15 at 18:52
  • don't pass the id as I mentioned above. just use the "getView()" method to get the parent view and everything will work just fine. I have tested the above code and then after posted it here. – Nilesh Singh Dec 30 '15 at 18:55
  • I'm testing this now and will get back to you shortly. I think what you are saying is to take out the fragment's coordinatorlayout view, leave in the parent's (activity's) coordinatorlayout view and the getView() method will walk up to the parent's coordinatorlayout view and the snackbar will show there. I'm going to test this out now. – Simon Dec 30 '15 at 19:03
  • sure, and also don't forget to accept the answer if the answer comes handy. :) – Nilesh Singh Dec 30 '15 at 19:05
  • OK - this solution is working. +1 and since i think this is the easiest way to make the snackbar walk up to the activity coordinatorlayout, i will accept your answer. Thanks! – Simon Dec 30 '15 at 19:10
1

I managed to solve this by following Leo's suggestion of passing in a reference to my activity's coordinatorlayout into my fragment and then using that coordinatorlayout to display my snackbar within my fragment.

So this is what I did in code.

This is my activity code:

    coordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordinatorlayout);
    TestFragment testFragment = new Fragment();

    //Needed for every fragment
    testFragment.setActivityCoordinatorLayout(coordinatorLayout); //passed the activity coordinatorlayout to my fragment.

In my fragment we get a reference to the activity's coordinatorlayout:

public void setActivityCoordinatorLayout(CoordinatorLayout activityCoordinatorLayout) {
    this.activityCoordinatorLayout = activityCoordinatorLayout;
}

Then we set the snackbar to show against this activity coordinatorlayout:

            Snackbar.make(activityCoordinatorLayout, "No internet", Snackbar.LENGTH_LONG)
                    .setAction("Retry", new View.OnClickListener() {
                        @Override
                        public void onClick(View v) { <YOUR CODE>}}).show();

This is however a long about way to get the code working. A quicker way is actually to use Nilesh's code and his getView method.

Simon
  • 19,658
  • 27
  • 149
  • 217