如何在屏幕顶部显示Snackbar

问题描述 投票:0回答:13

正如 Android 文档所述

Snackbars 提供有关操作的轻量级反馈。它们在移动设备上的屏幕底部显示一条简短的消息,在较大设备上的左下角显示一条简短消息。

有没有其他方法可以让

snackbars
显示在屏幕顶部而不是底部?

现在我正在做类似的事情,在屏幕底部显示

snackbar

Snackbar.make(findViewById(android.R.id.content), "Hello this is a snackbar!!!", 
Snackbar.LENGTH_LONG).setAction("Undo", mOnClickListener)
.setActionTextColor(Color.RED)
.show();
android material-design android-snackbar
13个回答
188
投票

可以使用以下方法使小吃栏出现在屏幕顶部:

Snackbar snack = Snackbar.make(parentLayout, str, Snackbar.LENGTH_LONG);
View view = snack.getView();
FrameLayout.LayoutParams params =(FrameLayout.LayoutParams)view.getLayoutParams();
params.gravity = Gravity.TOP;
view.setLayoutParams(params);
snack.show();

来自OP:

我必须更改第一行:

Snackbar snack = Snackbar.make(findViewById(android.R.id.content), "Had a snack at Snackbar", Snackbar.LENGTH_LONG);

56
投票
CoordinatorLayout coordinatorLayout=(CoordinatorLayout)findViewById(R.id.coordinatorLayout);
Snackbar snackbar = Snackbar.make(coordinatorLayout, "Text", Snackbar.LENGTH_LONG);
View view = snackbar.getView();
CoordinatorLayout.LayoutParams params=(CoordinatorLayout.LayoutParams)view.getLayoutParams();
params.gravity = Gravity.TOP;
view.setLayoutParams(params);
snackbar.show();

29
投票

科特林-

    val snackBarView = Snackbar.make(view, "SnackBar Message" , Snackbar.LENGTH_LONG)
    val view = snackBarView.view
    val params = view.layoutParams as FrameLayout.LayoutParams
    params.gravity = Gravity.TOP
    view.layoutParams = params
    view.background = ContextCompat.getDrawable(context,R.drawable.custom_drawable) // for custom background
    snackBarView.animationMode = BaseTransientBottomBar.ANIMATION_MODE_FADE
    snackBarView.show()

下面的行将解决动画问题。

snackBarView.animationMode = BaseTransientBottomBar.ANIMATION_MODE_FADE

替代解决方案-

snackBarView.anchorView = mention viewId above whom you want to show SnackBar


27
投票

您可以执行以下操作,将 SnackBar 放置在布局内的任何位置(此方法没有动画问题

1) 根据:

https://developer.android.com/reference/android/support/design/widget/Snackbar.html#make(android.view.View, java.lang.CharSequence, int)

Snackbar制作(查看视图, 字符序列文本, 持续时间)

创建一个 Snackbar 来显示消息 Snackbar 将尝试找到一个父视图来保存 Snackbar 的视图 赋予视图的值。 Snackbar 会沿着视图树向上走,试图 找到一个合适的父级,它被定义为 CoordinatorLayout 或 窗口装饰的内容视图,以先到者为准。

因此,只需在所需位置添加协调器布局并使用该协调器布局作为上面 Snackbar.make 方法中的视图参数,就可以将 SnackBar 放置在布局内的任何位置。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".MainActivity"
android:orientation="vertical"
android:id="@+id/rl"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">

<!-- Coordinator Layout used to position the SnackBar -->

<android.support.design.widget.CoordinatorLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/cl"
    android:layout_alignParentTop="true"
    android:background="@android:color/transparent">
</android.support.design.widget.CoordinatorLayout>

<!-- add your layout here -->

</RelativeLayout>

2) 用于显示 SnackBar 的协调器布局应位于所有其他视图的顶部(最高高度)。为此,可以在协调器布局上调用

bringToFront()
或提升协调器布局(添加 例如
android:elevation="10dp"

3)此时,snackBar 将显示在所需的位置,但snackBar 以从下到上的动画显示(默认行为)。为了实现从上到下的动画,您可以执行以下操作:

  • 将 Snackbar.make 方法中使用的协调器布局旋转 180 度

4)第3步之后,snackBar将以从上到下的动画显示,但消息和操作文本会旋转并且重力会反转,因此作为最后一步,我执行了以下操作:

  • 拿到SnackBar View,找到负责显示消息的TextView和负责操作的TextView的LinearLayout,并将父LinearLayout旋转180度

5) 示例:

public class MainActivity extends AppCompatActivity {

private final String TAG = MainActivity.class.getSimpleName();
private RelativeLayout rl;
private CoordinatorLayout cl;
private CoordinatorLayout cl1;
private CoordinatorLayout cl2;
private CoordinatorLayout cl3;
private CoordinatorLayout cl4;
private Snackbar snackbar_updated;
private Snackbar snackbar_updated1;
private Snackbar snackbar_updated2;
private Snackbar snackbar_updated3;
private Snackbar snackbar_updated4;
private Snackbar snackbar_ordinary;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    rl = (RelativeLayout) findViewById(R.id.rl);
    cl = (CoordinatorLayout) findViewById(R.id.cl);
    cl1 = (CoordinatorLayout) findViewById(R.id.cl1);
    cl2 = (CoordinatorLayout) findViewById(R.id.cl2);
    cl3 = (CoordinatorLayout) findViewById(R.id.cl3);
    cl4 = (CoordinatorLayout) findViewById(R.id.cl4);
    cl.bringToFront();
    cl1.bringToFront();
    cl2.bringToFront();
    cl3.bringToFront();
    cl4.bringToFront();

    snackbar_updated = Snackbar.make(cl, "Message", Snackbar.LENGTH_INDEFINITE);
    snackbar_updated.setAction("Ok", new View.OnClickListener() {
        @Override
        public void onClick(View view) {

        }
    });
    /** Snackbar message and action TextViews are placed inside a LinearLayout
     */
    final Snackbar.SnackbarLayout snackBarLayout = (Snackbar.SnackbarLayout) snackbar_updated.getView();
    for (int i = 0; i < snackBarLayout.getChildCount(); i++) {
        View parent = snackBarLayout.getChildAt(i);
        if (parent instanceof LinearLayout) {
            ((LinearLayout) parent).setRotation(180);
            break;
        }
    }

    snackbar_updated1 = Snackbar.make(cl1, "Message", Snackbar.LENGTH_INDEFINITE);
    snackbar_updated1.setAction("Ok", new View.OnClickListener() {
        @Override
        public void onClick(View view) {

        }
    });
    /** Snackbar message and action TextViews are placed inside a LinearLayout
     */
    final Snackbar.SnackbarLayout snackBarLayout1 = (Snackbar.SnackbarLayout) snackbar_updated1.getView();
    for (int i = 0; i < snackBarLayout1.getChildCount(); i++) {
        View parent = snackBarLayout1.getChildAt(i);
        if (parent instanceof LinearLayout) {
            ((LinearLayout) parent).setRotation(180);
            break;
        }
    }

    snackbar_updated2 = Snackbar.make(cl2, "Message", Snackbar.LENGTH_INDEFINITE);
    snackbar_updated2.setAction("Ok", new View.OnClickListener() {
        @Override
        public void onClick(View view) {

        }
    });

    snackbar_updated3 = Snackbar.make(cl3, "Message", Snackbar.LENGTH_INDEFINITE);
    snackbar_updated3.setAction("Ok", new View.OnClickListener() {
        @Override
        public void onClick(View view) {

        }
    });
    /** Snackbar message and action TextViews are placed inside a LinearLayout
     */
    Snackbar.SnackbarLayout snackBarLayout3 = (Snackbar.SnackbarLayout) snackbar_updated3.getView();
    for (int i = 0; i < snackBarLayout3.getChildCount(); i++) {
        View parent = snackBarLayout3.getChildAt(i);
        if (parent instanceof LinearLayout) {
            ((LinearLayout) parent).setRotation(180);
            break;
        }
    }

    snackbar_updated4 = Snackbar.make(cl4, "Message", Snackbar.LENGTH_INDEFINITE);
    snackbar_updated4.setAction("Ok", new View.OnClickListener() {
        @Override
        public void onClick(View view) {

        }
    });

    snackbar_ordinary = Snackbar.make(rl, "Message", Snackbar.LENGTH_INDEFINITE);
    snackbar_ordinary.setAction("Ok", new View.OnClickListener() {
        @Override
        public void onClick(View view) {

        }
    });

    rl.post(new Runnable() {
        @Override
        public void run() {
            snackbar_updated.show();
            rl.postDelayed(new Runnable() {
                @Override
                public void run() {
                    snackbar_updated1.show();
                    rl.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            snackbar_updated2.show();
                            rl.postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    snackbar_updated3.show();
                                    rl.postDelayed(new Runnable() {
                                        @Override
                                        public void run() {
                                            snackbar_updated4.show();
                                            rl.postDelayed(new Runnable() {
                                                @Override
                                                public void run() {
                                                    snackbar_ordinary.show();
                                                }
                                            }, 2000);
                                        }
                                    }, 2000);
                                }
                            }, 2000);
                        }
                    }, 2000);
                }
            }, 2000);
        }
    });

}

}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".MainActivity"
android:orientation="vertical"
android:id="@+id/rl"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">

<!-- Coordinator Layout used to position the SnackBar -->

<android.support.design.widget.CoordinatorLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/cl"
    android:rotation="180"
    android:layout_alignParentTop="true"
    android:background="@android:color/transparent">
</android.support.design.widget.CoordinatorLayout>

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_alignParentTop="true"
    android:orientation="vertical">

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

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:itemIconTint="#333"
        app:itemTextColor="#333"
        app:layout_collapseMode="pin"
        app:layout_scrollFlags="scroll|enterAlways"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Dark"
        app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>

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

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_below="@id/appbar"
        android:layout_gravity="bottom">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="30dp"
            android:id="@+id/tv_top"
            android:text="Layout Top"
            android:gravity="center"
            android:textSize="15sp"
            android:textColor="@android:color/white"
            android:layout_alignParentTop="true"
            android:background="@color/colorAccent">
        </TextView>

        <!-- Coordinator Layout used to position the SnackBar -->

        <android.support.design.widget.CoordinatorLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/cl1"
            android:rotation="180"
            android:layout_below="@id/tv_top"
            android:background="@android:color/transparent">
        </android.support.design.widget.CoordinatorLayout>


        <!-- Coordinator Layout used to position the SnackBar -->

        <android.support.design.widget.CoordinatorLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/cl2"
            android:paddingBottom="75dp"
            android:layout_centerInParent="true"
            android:background="@android:color/transparent">
        </android.support.design.widget.CoordinatorLayout>

        <!-- Coordinator Layout used to position the SnackBar -->

        <TextView
            android:layout_width="match_parent"
            android:layout_height="30dp"
            android:id="@+id/tv_center"
            android:text="Center"
            android:gravity="center"
            android:textSize="15sp"
            android:layout_centerInParent="true"
            android:textColor="@android:color/white"
            android:background="@color/colorAccent">
        </TextView>

        <android.support.design.widget.CoordinatorLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/cl3"
            android:rotation="180"
            android:paddingBottom="75dp"
            android:layout_centerInParent="true"
            android:background="@android:color/transparent">
        </android.support.design.widget.CoordinatorLayout>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="30dp"
            android:id="@+id/tv_bottom"
            android:text="Layout Bottom"
            android:gravity="center"
            android:textSize="15sp"
            android:textColor="@android:color/white"
            android:layout_alignParentBottom="true"
            android:background="@color/colorAccent">
        </TextView>

        <!-- Coordinator Layout used to position the SnackBar -->

        <android.support.design.widget.CoordinatorLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/cl4"
            android:layout_above="@id/tv_bottom"
            android:background="@android:color/transparent">
        </android.support.design.widget.CoordinatorLayout>


    </RelativeLayout>

</RelativeLayout>

</RelativeLayout>

6) 结果:


17
投票

上述解决方案的组合:

final ViewGroup.LayoutParams params = snackbar.getView().getLayoutParams();
if (params instanceof CoordinatorLayout.LayoutParams) {
    ((CoordinatorLayout.LayoutParams) params).gravity = Gravity.TOP;
} else {
    ((FrameLayout.LayoutParams) params).gravity = Gravity.TOP;
}
snackbar.getView().setLayoutParams(params);

仍然受到动画不正确的困扰。


9
投票

这使得 Snackbar 出现在顶部,而不会出现过渡中奇怪的幻灯片。

Kotlin 中最好的简单解决方案:

    val snackbar = Snackbar.make(view, string, Snackbar.LENGTH_LONG)
    val layoutParams = LayoutParams(snackbar.view.layoutParams)

    layoutParams.gravity = Gravity.TOP
    snackbar.view.setPadding(0, 10, 0, 0)
    snackbar.view.layoutParams = layoutParams
    snackbar.animationMode = BaseTransientBottomBar.ANIMATION_MODE_FADE
    snackbar.show()

7
投票

惯用的 Kotlin 版本

snackbar.view.layoutParams = (snackbar.view.layoutParams as FrameLayout.LayoutParams).apply {
  gravity = Gravity.TOP
}

Kotlin 扩展

/** Kotlin extension that adds this snackbar at the top of the screen. */
fun Snackbar.gravityTop() {
  this.view.layoutParams = (this.view.layoutParams as FrameLayout.LayoutParams).apply {
    gravity = Gravity.TOP
  }
}

那就拨打:

snackbar.gravityTop()

3
投票

在显示 Snackbar 之前,请添加以下代码

View snackbarView = snackbar.getView();

FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) snackbarView.getLayoutParams();
params.gravity = Gravity.TOP;
snackbarView.setLayoutParams(params);
snackbarView.startAnimation(AnimationUtils.loadAnimation(host, R.anim.slide_in_snack_bar));

当解雇()时

View snackbarView = snackbar.getView();
  
snackbarView.startAnimation(AnimationUtils.loadAnimation(_snackbar.getContext(), R.anim.slide_out_snack_bar));
snackbar.dismiss()

slide_in_snack_bar.xml

<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_longAnimTime"
android:fromYDelta="-100%p"
android:toYDelta="0%p" />

slide_out_snack_bar.xml

<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_longAnimTime"
android:fromYDelta="0%p"
android:toYDelta="-100%p" />

1
投票

如果您使用

Constraintlayoutas
作为根父级,在指南和
CoordinatorLayout
的帮助下,您可以尝试以下操作:

更改Guideline内的值:layout_constraintGuide_end =“您的底部边距值”,如下例所示。

<androidx.coordinatorlayout.widget.CoordinatorLayout
    android:id="@+id/coordinator"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:layout_constraintTop_toBottomOf="@id/guideline3" />

<androidx.constraintlayout.widget.Guideline
    android:id="@+id/guideline3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    app:layout_constraintGuide_end="150dp" />

在活动中,您可以传递 CoordinatorLayout 作为小吃栏的视图

mSnackBar = Snackbar.make(
            coordinator,
            getString(R.string.no_internet_connection),
            Snackbar.LENGTH_INDEFINITE
        )
        mSnackBar.show()

1
投票

为什么不将其锚定到其他视图,假设您在布局中有其他视图,只需将小吃栏锚定到某个视图,以便它显示在那里,例如:

<LinearLayout>
......<Button>

<LinearLayout>
<TextView>
</LinearLayout>
</LinearLayout>

代码:

Snackbar snackbar = Snackbar.make(view,message, snackbar.LENGTH_SHORT).setAnchorView(R.id.reg_button);

R.id.reg_button 是布局中的按钮,它可以位于小吃栏将显示的任何位置 无需使用任何框架等应用程序将按预期运行不会崩溃


0
投票

2年后,这是我的解决方案..

设置顶部和底部边距会更改效果结果,...我已尝试添加尽可能多的自定义选项,覆盖动画是此处未写的另一个选项。

感谢大家对几个问题的回答...

{
    // usage for setSnackBar
    int view = R.id.toolbar;
    String snackMessage = "";
    boolean useAction = false;
    Runnable ifUseActionRunnable = null;
    String actionText = "";
    int leftMargin = 0;
    int topMargin = 0;
    int rightMargin = 0;
    int bottomMargin = 0;
    int backgroundColour = Color.BLACK;
    int textColor = Color.WHITE;
    int duration = Snackbar.LENGTH_LONG;
    setSnackBar(view, snackMessage, useAction, ifUseActionRunnable, actionText, leftMargin, topMargin, rightMargin, bottomMargin, backgroundColour, textColor, duration);

}

Snackbar snb;
public void setSnackBar(int targetView, String snackMessage, boolean useAction, final Runnable ifUseActionRunnable, String actionText , int leftMargin, int topMargin, int rightMargin, int bottomMargin, int backgroundColour, int textColor, int duration)
{
    snb = Snackbar.make(findViewById(targetView), snackMessage, duration);
    View view = snb.getView();
    view.setBackgroundColor(backgroundColour);
    snb.setActionTextColor(textColor);
    FrameLayout.LayoutParams params =(FrameLayout.LayoutParams)view.getLayoutParams();
    params.gravity =  Gravity.CENTER_HORIZONTAL | Gravity.TOP;
    params.setMargins(leftMargin, topMargin, rightMargin, bottomMargin);
    view.setLayoutParams(params);
    if (useAction)
    {
        snb.setAction(actionText, new View.OnClickListener(){
                @Override
                public void onClick(View p1)
                {
                    ifUseActionRunnable.run();

                }
            });
    }
    if (snb.isShown())
    {
        snb.dismiss();
        snb.show();
    }
    else
    {
        snb.show();
    }
}

0
投票

在屏幕顶部显示 Snackbar (kotlin)

// Custom snackbar : banner model
            val customSnackBar   = Snackbar.make(snackbar_id, "", Snackbar.LENGTH_INDEFINITE)

            val view = customSnackBar.view
            val params = view.layoutParams as CoordinatorLayout.LayoutParams
            params.gravity = Gravity.TOP
            view.layoutParams = params

            val layout           = customSnackBar.view as Snackbar.SnackbarLayout
            val customSnackView  = layoutInflater.inflate(R.layout.snackbar_banner, null)

            val actionButton1   = customSnackView.findViewById(R.id.action_button_1) as MaterialButton
            actionButton1.setOnClickListener {
                customSnackBar.dismiss()
            }
            val actionButton   = customSnackView.findViewById(R.id.action_button_2) as MaterialButton
            actionButton.setOnClickListener {
                customSnackBar.dismiss()
            }

            // We can also customize the above controls
            layout.setPadding(0, 0, 0, 0)
            layout.addView(customSnackView, 0)


            customSnackBar.show()

XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:background="@android:color/white"
   >

    <TextView
        android:padding="16dp"
        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/snackbar_banner_message"
        android:textColor="@android:color/black"
        android:textSize="16sp" />

    <LinearLayout
        android:gravity="end"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:orientation="horizontal">

        <com.google.android.material.button.MaterialButton
            android:id="@+id/action_button_1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginEnd="8dp"
            android:layout_weight="1"
            android:background="@android:color/black"
            android:text="Close"
            style="@style/Widget.MaterialComponents.Button.TextButton"
           />

        <com.google.android.material.button.MaterialButton
            android:id="@+id/action_button_2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="@android:color/black"
            android:text="Fix it"
            android:textStyle="bold"
            style="@style/Widget.MaterialComponents.Button.TextButton"
           />

    </LinearLayout>

</LinearLayout>


0
投票

使用上面讨论的方法,我做了一个简单的项目,使小吃栏从顶部出现,并且没有奇怪的动画。使用小吃栏中的 LayoutParams 并使用自定义布局来实现此目的。 请参考我的github仓库: 这里 -> TopSnackbar

© www.soinside.com 2019 - 2024. All rights reserved.