Android:当工具栏显示时显示 snackbar

4
这是WhatsApp在您不向上滚动时的样子。工具栏和标签布局都显示出来。
屏幕截图1:

whatsapp1

这是WhatsApp,当你向上滚动时,工具栏会隐藏起来。
屏幕截图2:

whatspp2

有一份指南可以教你如何创建这个效果。我已经按照它的步骤操作,在我的应用程序中成功实现了这个效果。

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

link from guide

我的问题是如何在显示工具栏(如SCREENSHOT1所示)时显示一个Snackbar。当我尝试在显示工具栏时显示Snackbar时,它实际上会显示在屏幕下方,因此用户无法看到。只有当用户向上滚动并隐藏工具栏时,Snackbar才会可见。
我用于我的应用程序的xml类似于指南中使用的https://github.com/mzgreen/HideOnScrollExample/blob/master/app/src/main/res/layout/activity_part_three.xml。我已按以下链接的代码进行了复制和粘贴:
<?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>

有谁知道我如何在工具栏可见时显示Snackbar?

编辑:

因为布局方案包含选项卡布局,每个选项卡布局都显示一个片段,所以我正在尝试针对每个片段显示Snackbar,而不是在活动级别上显示。我实际上开始认为这可能无法针对每个片段显示Snackbar,实际上需要通过将每个3个片段的侦听器与主活动绑定来完成,然后必须在主活动中显示Snackbar。

这是我的一个片段的XML:

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

你是否将CoordinatorView传递给Snackbar.make(View, String, int)? - Jared Rummler
是的,这是显示它的标准代码。 - Simon
3个回答

2
尝试将您的ViewPager的高度设置为wrap_content
CoordinatorLayout应该使用match_parent来保持其尺寸不变。
此外,请确保将您的CoordinatorLayout的后代视图传递给Snackbar.make
根据评论更新:
Snackbar 将从您提供的视图开始向上遍历视图层次结构,并将自己附加到它找到的第一个CoordinatorLayout或窗口装饰的内容视图(如果找不到)。
如果您在片段中嵌套了CoordinatorLayouts,则需要确保子CoordinatorLayouts不会溢出其容器,这可能有些棘手。
在我看来,最好删除片段中的CoordinatorLayouts,并从您的片段中为Snackbar.make提供一个视图。它将愉快地向上遍历层次结构(甚至超出片段范围),以达到您活动中的CoordinatorLayout。
如果你这样做,回调函数会像往常一样工作,但请确保将你使用的任何回调函数标记为static以避免在你的片段被移除后Snackbar仍停留在屏幕上而导致泄漏
这可能会发生,因为Snackbar将持有对你的回调函数的引用,而这个回调函数又可以持有对你的片段的引用。如果你需要一个对片段或上下文的引用,请使用弱引用。

将viewpager的高度更改为wrap_content并不能解决问题。此外,viewpager包含片段,每个片段都有coordinatorlayout视图。也许我在我的问题中没有表达清楚,很快就会进行编辑,但我正在尝试使snackbar在每个片段内部显示,而不是在活动中显示。不确定是否可能,也许解决这个问题最简单的方法实际上是为活动创建一个snackbar,并将监听器从片段绑定到活动,以便在片段调用时活动将显示snackbar。 - Simon
我已经更新了答案,并添加了一个关于如何在片段中附加Snackbar的部分。 - Leo Nikkilä
抱歉 - 我对你的回答有疑问 - snackbar 在每个片段内触发。假设片段进行网络调用,其中一个失败了。snackbar 应该显示“无网络连接”,而使用我的当前设置,它将附加到名为“@+id/snackbarPosition”的 coordinatorlayout 上。我需要它向上移动到活动的 coordinatorlayout,即“@+id/coordinatorLayout”。这可能吗?我应该只是从我的活动传递一个引用到片段的“@+id/coordinatorLayout”,并在我的 snackbar.make 中使用该引用吗? - Simon
你基本上有两个选项来实现这个:要么删除内部的CoordinatorLayouts并从你的布局中传递任何视图给Snackbar.make,要么保留内部布局并从你的Fragment根视图上方(即从你的Activity中)传递一个视图给Snackbar.make。在Fragment中引用外部布局是实现后者的可行方法,但我建议尽可能消除嵌套的CoordinatorLayouts,因为它们很可能会在以后造成更多麻烦。 - Leo Nikkilä
谢谢 - 你的第二个选项实际上是正确答案。我刚测试过了,它可以工作。我也会发布我的解决方案。+1并感谢你的帮助。 - Simon

2
很简单。只需将viewPager用作视图即可完成。它看起来像这样:
Snackbar snackbar = Snackbar.make(findViewById(R.id.viewPager), "Your Message", Snackbar.LENGTH_LONG);
    snackbar.getView().setBackgroundColor(Color.parseColor("#00b8ba"));
    snackbar.show();

请确保将findViewById(R.id.viewPager)作为视图传递。

顺便提一下,viewPager的定义如下:

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

对于不同的片段,请使用以下内容(第一个片段):

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

第二段:

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

嗨,我觉得我在最初的问题中没有表达清楚,但我正在尝试在每个片段中显示 snackbar 而不是在活动级别上显示。如果我在活动级别上执行此操作,您的答案将起作用,但您能想到在片段级别上起作用的解决方案吗? - Simon
抱歉,您如何在另一个活动中显示片段调用的响应?您可能需要保存数据,当特定的活动打开并检测到错误发生时,它将显示附加到"@+id/coordinatorLayout"的snackbar。如果一切顺利(或者在活动中持久化和接收到的数据为空),则不会发生任何事情。 - Nilesh Singh
它不是在另一个活动中 - 片段嵌套在活动中,该活动持有协调器布局“@+id/coordinatorLayout”。当活动显示时,片段也会随之显示。目前,我将 snackbar 传递给了我的片段内的 coordinatorlayout,这就是为什么直到滚动上去才显示的原因。我刚刚通过将活动 coordinatorlayout 的引用从我的活动传递到我的片段中来解决了这个问题,现在它可以正常工作了。我很快会发布一个解决方案。 - Simon
不要像我上面提到的那样传递id,只需使用“getView()”方法获取父视图,一切都会正常工作。我已经测试了上面的代码,然后在这里发布了它。 - Nilesh Singh
当然,如果答案有用的话,也不要忘记接受答案。 :) - Nilesh Singh
显示剩余3条评论

1
我通过遵循Leo的建议,在我的片段中传递了对活动协调器布局的引用,然后使用该协调器布局在我的片段中显示了snackbar,解决了这个问题。
以下是我的代码:
这是我的活动代码:
    coordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordinatorlayout);
    TestFragment testFragment = new Fragment();

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

在我的片段中,我们获取到了活动的coordinatorlayout的引用:
public void setActivityCoordinatorLayout(CoordinatorLayout activityCoordinatorLayout) {
    this.activityCoordinatorLayout = activityCoordinatorLayout;
}

然后,我们将snackbar设置为针对此活动协调器布局显示:
            Snackbar.make(activityCoordinatorLayout, "No internet", Snackbar.LENGTH_LONG)
                    .setAction("Retry", new View.OnClickListener() {
                        @Override
                        public void onClick(View v) { <YOUR CODE>}}).show();

然而,这种方法实现代码的效率较低。更快的方法是使用Nilesh的代码和他的getView方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接