如何固定 Snackbar 的高度和位置?

How to fix the Snackbar height and position?

Android 支持库 24.1.1 上,Snackbar 工作正常:

然后从 Android 支持库 24.2.0 开始,Snackbar 开始表现如下:

在库revision history上,有如下语句:

Behavior changes: Snackbar now draws behind the navigation bar if the status bar is translucent.

但问题是我的应用程序是全屏的,没有导航栏或状态栏。我该如何解决?

在你的小吃店里使用这个,

FrameLayout.LayoutParams params =(FrameLayout.LayoutParams)view.getLayoutParams();
    params.gravity = Gravity.BOTTOM;

查看此答案 并替换

 params.setMargins(params.leftMargin,
            params.topMargin,
            params.rightMargin,
            params.bottomMargin + ScreenUtils.getNavigationBarHeight(activity));

 params.setMargins(params.leftMargin,
            params.topMargin,
            params.rightMargin,
            params.bottomMargin - ScreenUtils.getNavigationBarHeight(activity));

我最近通过从 Snackbar 视图的底部边缘减去导航栏高度解决了这个问题。

首先我们需要导航栏的高度。我在此处标记为正确的答案中找到了代码:

接下来,使用以下代码调整 Snackbar 底部边距:

final Snackbar snackbar = Snackbar.make(findViewById(R.id.fullscreen_content),
                message, Snackbar.LENGTH_LONG);

View snackbarView = snackbar.getView();

// Adjust Snackbar height for fullscreen immersive mode
int navbarHeight = getNavigationBarSize(this).y;

CoordinatorLayout.LayoutParams parentParams = (CoordinatorLayout.LayoutParams) snackbarView.getLayoutParams();
    parentParams.setMargins(0, 0, 0, 0 - navbarHeight);
    snackbarView.setLayoutParams(parentParams);

snackbar.show();

请注意,我使用了 CoordinatorLayout 的 LayoutParams。您应该将 CoordinatorLayout 替换为您传递给 Snackbar.make() 函数的任何父布局类型(在我的例子中,R.id.fullscreen_content 是一个 CoordinatorLayout)。使用 CoordinatorLayout 的好处是它允许通过滑动作为标准行为来关闭 Snackbars。

接受的答案适用于旧版本的支持库,其中 Snackbar 只是一个矩形视图。通过将边距更改为负值实际发生的只是切断 SnackbarLayout 的底部(Snackbar 的容器布局),因此 Snackbar 具有圆角的较新版本这个解决方案看起来很糟糕。

线索在代码中:https://github.com/material-components/material-components-android/blob/cd59e98f7e2185ddb075ff0fc91f29765d562968/lib/java/com/google/android/material/snackbar/BaseTransientBottomBar.java#L272

实际发生的是填充被添加到容器中,因此正确固定高度的方法是将填充重置为正确的数量。您可以通过添加额外的 OnApplyWindowInsetsListener 来做到这一点,如下所示(将底部填充设置为与顶部相同使 Snackbar 看起来正常):

ViewCompat.setOnApplyWindowInsetsListener(snackbar.view) { v, insets ->
    v.setPadding(v.paddingLeft, v.paddingTop, v.paddingRight, v.paddingTop)
    insets
}

然后,由于 Snackbar 现在是正确的高度但出现在半透明导航栏后面,您可以通过底部插图的值增加底部边距:

ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets ->
    v.setPadding(v.paddingLeft, v.paddingTop, v.paddingRight, v.paddingTop)

    val params = v.layoutParams as ViewGroup.MarginLayoutParams
    params.updateMargins(
        params.leftMargin,
        params.topMargin,
        params.rightMargin,
        params.bottomMargin + insets.systemWindowInsetBottom
    )
    v.layoutParams = params

    insets
}

这实际上已在 Material 1.1.0 alpha 库中修复(该库现在更改边距而不是填充),但它们可能尚未准备好用于生产。

如果您只关心身高而不是位置,那么请准备好让您大吃一惊! :D

将您的小吃栏内容设置为:

Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Text(
            'Your SnackBar message',
          ),
          SizedBox(
            height: 70, // Your desired height
          )
        ],
      ))

另一种方式是

Snackbar snackbar = Snackbar.make(view, ...);
View snackBarView = snackbar.getView();

ViewCompat.setFitsSystemWindows(snackBarView, false);
ViewCompat.setOnApplyWindowInsetsListener(snackBarView, null);

这将在沉浸式模式下禁用额外的底部填充。

现在是 2020 年,我也不知道这是否相关,但是当我使用 android 10 手势导航时,我的小吃店底部有一些填充物。 None 以上适用于我的情况。我终于用一条超级简单的线修复了它:

val snackbar = Snackbar.make(view, message, duration)
snackbar.isGestureInsetBottomIgnored = true // here
snackbar.show()

希望对您有所帮助。