如何在屏幕顶部显示Snackbar

Pan*_*kaj 8 android android-snackbar

正如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();
Run Code Online (Sandbox Code Playgroud)

Ada*_*dav 157

可以使用以下方法使快餐栏显示在屏幕顶部:

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();
Run Code Online (Sandbox Code Playgroud)

来自OP:

我不得不改变第一行:

Snackbar snack = Snackbar.make(findViewById(android.R.id.content), "Had a snack at Snackbar", Snackbar.LENGTH_LONG);
Run Code Online (Sandbox Code Playgroud)

  • `SnackBar`上的动画向上滑动,这看起来很可怕.我还没有尝试过,但是这是一个库项目,它显示了一个带有正确动画的`SnackBar`:https://github.com/AndreiD/TSnackBar我觉得我在IRC上的## java. (30认同)
  • 如果您在层次结构中的某处使用协调器布局,则此代码会因*ClassCastException而崩溃,而CoordinatorLayout $ LayoutParams无法转换为FrameLayout $ LayoutParams*.*支持v24*仅使用FrameLayout作为snackbar容器,如果它没有找到*CoordinatorLayout*祖先或者它的id是*android.R.id.content*.有关实现的详细信息,请参阅*SnackBar.findSuitableParent*.您可以通过将FrameLayout的id设置为*android.R.id.content*来破解系统,但这可能会在将来停止工作. (5认同)
  • 这是非常难看的解决方案.如果您使用任何布局(FrameLayout除外),它将崩溃. (5认同)

小智 39

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();
Run Code Online (Sandbox Code Playgroud)

  • 这个是有效的.Adarsh Yadav的解决方案是将CoordinatorLayout强制转换为FrameLayout,可能有机会崩溃应用程序 (9认同)
  • 安全,使用`FrameLayout.LayoutParams`可能会导致崩溃.`CoordinatorLayout.LayoutParams`工作正常. (3认同)
  • 他们因这个答案获得了非常罕见的徽章!总共三个答案之一。回来吧,维贾扬,我们想念你。 (2认同)

Bra*_*ovo 18

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

1) 根据:

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

Snackbar make(视图视图、CharSequence 文本、int 持续时间)

制作一个 Snackbar 以显示一条消息 Snackbar 将尝试从给定的值中找到一个父视图来保存 Snackbar 的视图。Snackbar 将沿着视图树向上走,试图找到一个合适的父视图,它被定义为 CoordinatorLayout 或窗口装饰的内容视图,以先到者为准。

因此,只需在所需位置添加 Coordinator Layout 并使用该 Coordinator Layout 作为上述 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>
Run Code Online (Sandbox Code Playgroud)

2) 用于显示 SnackBar 的 Coordinator Layout 应该位于所有其他视图的顶部(最高海拔)。为了做到这一点,可以调用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);
        }
    });

}

}
Run Code Online (Sandbox Code Playgroud)

活动_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>
Run Code Online (Sandbox Code Playgroud)

6) 结果:

结果


小智 16

科特林-

    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()
Run Code Online (Sandbox Code Playgroud)

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

snackBarView.animationMode = BaseTransientBottomBar.ANIMATION_MODE_FADE
Run Code Online (Sandbox Code Playgroud)

替代解决方案- snackBarView.anchorView = mention viewId above whom you want to show SnackBar


Mar*_*sny 11

以上组合解决方案:

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);
Run Code Online (Sandbox Code Playgroud)

仍然受到不正确动画的影响.


Jul*_*eis 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()
Run Code Online (Sandbox Code Playgroud)


Dam*_*tes 7

惯用的 Kotlin 版本

snackbar.view.layoutParams = (snackbar.view.layoutParams as FrameLayout.LayoutParams).apply {
  gravity = Gravity.TOP
}
Run Code Online (Sandbox Code Playgroud)

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
  }
}
Run Code Online (Sandbox Code Playgroud)

然后只需调用:

snackbar.gravityTop()
Run Code Online (Sandbox Code Playgroud)