[英]Move snackbar above the bottom bar
I am facing some problems with new bottom bar.我在使用新底栏时遇到了一些问题。
I can't force to move the snackbar above the bottom bar (this is how design guideline told me should be https://www.google.com/design/spec/components/bottom-navigation.html#bottom-navigation-specs ).我不能强制将小吃栏移到底部栏上方(这是设计指南告诉我的方式应该是https://www.google.com/design/spec/components/bottom-navigation.html#bottom-navigation-specs )。
This is my activity_main.xml这是我的activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="@layout/app_bar_main_activity"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main_activity"
app:menu="@menu/activity_main_drawer" />
</android.support.v4.widget.DrawerLayout>
This is my app_bar_main_activity.xml这是我的 app_bar_main_activity.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"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="test.tab_activity">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/appbar_padding_top"
android:theme="@style/MyAppTheme.NoActionBar.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/main_activity_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/MyAppTheme.NoActionBar.PopupOverlay">
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
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_add_white_24dp" />
<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
style="@style/AppTabLayout"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="?attr/colorPrimary"
/>
</LinearLayout>
The snackbar in main_activity.java looks like this main_activity.java 中的小吃店看起来像这样
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(findViewById(R.id.main_content), "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
With the material components library you can use the setAnchorView
method to make a Snackbar
appear above a specific view.使用材质组件库,您可以使用
setAnchorView
方法使Snackbar
出现在特定视图上方。
In your case if you are using a BottomAppBar
and a fab, you should define the fab in the setAanchorView
.在您的情况下,如果您使用
BottomAppBar
和 fab,则应在setAanchorView
定义fab 。 Something like:类似的东西:
FloatingActionButton fab = findViewById(R.id.fab);
Snackbar snackbar = Snackbar.make(view, "Snackbar over BottomAppBar", Snackbar.LENGTH_LONG);
snackbar.setAnchorView(fab);
The result:结果:
With a BottomNavigationView
you can define it as anchorView:使用
BottomNavigationView
您可以将其定义为anchorView:
Snackbar snackbar = Snackbar.make(view,"Snackbar over BottomNav",Snackbar.LENGTH_INDEFINITE);
snackbar.setAnchorView(bottomNavigationView);
snackbar.show();
Result:结果:
You can do this programmatically without cluttering your xml with extra CoordinatorLayouts by changing the snackbar's margins.您可以通过更改小吃店的边距以编程方式执行此操作,而不会用额外的 CoordinatorLayouts 使您的 xml 混乱。
Java example: Java示例:
Snackbar snack = Snackbar.make(findViewById(R.id.coordinatorLayout),
"Your message", Snackbar.LENGTH_LONG);
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams)
snack.getView().getLayoutParams();
params.setMargins(leftMargin, topMargin, rightMargin, bottomBar.height);
snack.getView().setLayoutParams(params);
snack.show();
Kotlin single line: Kotlin 单行:
Snackbar.make(coordinatorLayout, "Your message", Snackbar.LENGTH_LONG).apply {view.layoutParams = (view.layoutParams as CoordinatorLayout.LayoutParams).apply {setMargins(leftMargin, topMargin, rightMargin, bottomBar.height)}}.show()
Assuming your are working with CoordinatorLayout you can modify the Snackbar's layoutparams before calling show().假设您正在使用 CoordinatorLayout,您可以在调用 show() 之前修改 Snackbar 的 layoutparams。 By setting the anchorId and anchorGravity the snackBar will display above the bottom nav bar:
通过设置 anchorId 和 anchorGravity,snackBar 将显示在底部导航栏上方:
val layoutParams = snackbar.view.layoutParams as CoordinatorLayout.LayoutParams
layoutParams.anchorId = R.id.navigation //Id for your bottomNavBar or TabLayout
layoutParams.anchorGravity = Gravity.TOP
layoutParams.gravity = Gravity.TOP
snackbar.view.layoutParams = layoutParams
replace your xml ->替换你的 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"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="test.tab_activity">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/main_activity_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways">
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/placeSnackBar">
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
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_menu_gallery" />
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="?attr/colorPrimary" />
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
and The Snackbar code will be和 Snackbar 代码将是
Snackbar.make(findViewById(R.id.placeSnackBar), "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
There is great article about how to use it HERE .有一个关于如何使用它的优秀文章这里。 There you will know how to make snackbar above
BottomNavigationBar
在那里你会知道如何在底部导航栏上方
BottomNavigationBar
Basically the code below presents most common usage of Toolbar
together with BottomNavigationBar
and FrameLayout
as Fragment container基本上,下面的代码展示了
Toolbar
最常见的用法以及作为 Fragment 容器的BottomNavigationBar
和FrameLayout
Important!重要! Notice that
请注意
BottomNavigationView
uses layout_behaviour to handle scrolling and SnackBar position BottomNavigationView
使用layout_behaviour来处理滚动和 SnackBar 位置
<android.support.design.widget.AppBarLayout android:id="@+id/myAppBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:descendantFocusability="beforeDescendants" android:focusableInTouchMode="true" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:contentInsetStart="0dp" app:layout_scrollFlags="scroll|enterAlways" app:popupTheme="@style/AppTheme.PopupOverlay"/> </android.support.design.widget.AppBarLayout> <FrameLayout android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> <android.support.design.widget.BottomNavigationView android:id="@+id/navigation_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" app:menu="@menu/bottom_navigation" app:layout_behavior="murt.shoppinglistapp.ui.BottomNavigationBehavior" android:background="?android:attr/windowBackground" /> <android.support.design.widget.FloatingActionButton android:id="@+id/fab_add_shopping_list" android:layout_width="wrap_content" android:layout_height="wrap_content" app:useCompatPadding="true" app:srcCompat="@drawable/ic_add_24" app:layout_anchor="@id/navigation_bar" app:layout_anchorGravity="top|right" android:layout_gravity="top" />
Implmenetation of Behaviour don't hesitate to use that !行为的实现不要犹豫使用它! It's easy and friendly ;) (scrolling)
它既简单又友好;)(滚动)
class BottomNavigationBehavior : CoordinatorLayout.Behavior<BottomNavigationView> {
constructor(): super()
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
override fun layoutDependsOn(parent: CoordinatorLayout, child: BottomNavigationView,
dependency: View): Boolean {
if (dependency is Snackbar.SnackbarLayout) {
updateSnackbar(child, dependency)
}
return super.layoutDependsOn(parent, child, dependency)
}
private fun updateSnackbar(child: View, snackbarLayout: Snackbar.SnackbarLayout) {
if (snackbarLayout.layoutParams is CoordinatorLayout.LayoutParams) {
val params = snackbarLayout.layoutParams as CoordinatorLayout.LayoutParams
params.anchorId = child.id
params.anchorGravity = Gravity.TOP
params.gravity = Gravity.TOP
snackbarLayout.layoutParams = params
}
}
override fun onStartNestedScroll(
coordinatorLayout: CoordinatorLayout,
child: BottomNavigationView,
directTargetChild: View,
target: View,
nestedScrollAxes: Int
): Boolean {
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL
}
override fun onNestedPreScroll(
coordinatorLayout: CoordinatorLayout,
child: BottomNavigationView,
target: View,
dx: Int,
dy: Int,
consumed: IntArray
) {
if (dy < 0) {
showBottomNavigationView(child)
} else if (dy > 0) {
hideBottomNavigationView(child)
}
}
private fun hideBottomNavigationView(view: BottomNavigationView) {
view.animate().translationY(view.height.toFloat())
}
private fun showBottomNavigationView(view: BottomNavigationView) {
view.animate().translationY(0f)
}
}
There is a simple way, with the new Material Design:有一个简单的方法,使用新的材料设计:
Snackbar snackbar= Snackbar.make(view, text, duration);
snackbar.setAnchorView(bottomBar);
So the Snackbar
will show above the BottomNavigationView
.因此
Snackbar
将显示在BottomNavigationView
。
It can be done simply if the parent layout was Coordinator layout.如果父布局是协调器布局,则可以简单地完成。
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams)
snackbar.getView().getLayoutParams();
params.setAnchorId(R.id.navigation); //id of the bottom navigation view
params.gravity = Gravity.TOP;
params.anchorGravity = Gravity.TOP;
snackbar.getView().setLayoutParams(params);
为了实现这一点,您必须注意您提供给小吃店的 ViewGroup 是一个CoordinatorLayout否则小吃店不会显示在底部导航菜单上方。
I am using the BottomNavigationView and Snackbar from the design support library version 25.3.1 on target OS kitkat, lollipop and Marshmallow.我在目标操作系统 kitkat、棒棒糖和棉花糖上使用了设计支持库版本 25.3.1 中的 BottomNavigationView 和 Snackbar。 On lollipop and above Snackbar is hiding behind BottomNavigationView but in Kitkat BottomNavigationView is hidden behind Snackbar.
在棒棒糖和上面 Snackbar 隐藏在 BottomNavigationView 后面,但在 Kitkat BottomNavigationView 隐藏在 Snackbar 后面。
I tried to show the Snackbar with a different approach.我试图用不同的方法展示 Snackbar。 When the Snackbar is shown the BottomNavigationView is translated on Y-axis(scrolled down) using the translationY property and Interpolator .
当显示 Snackbar 时,BottomNavigationView 使用translationY 属性和 Interpolator在 Y 轴上平移(向下滚动)。 Once Snackbar is gone, the BottomNavigationView appears again with the same translationY property.
一旦 Snackbar 消失,BottomNavigationView 会再次出现,并具有相同的 translationY 属性。
Hiding the BottomNavigationView (towards bottom):隐藏底部导航视图(朝底部):
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) bottomNavigationView.getLayoutParams();
bottomNavigationView.animate().translationY(bottomNavigationView.getHeight() + layoutParams.bottomMargin).setInterpolator(new LinearInterpolator()).start();
Showing the BottomNavigationView back on screen:在屏幕上显示 BottomNavigationView:
bottomNavigationView.animate().translationY(0).setInterpolator(new LinearInterpolator()).start();
Snackbar outerSnackBar = Snackbar.make(findViewById(android.R.id.content), "Your text", Snackbar.LENGTH_INDEFINITE);
View view = outerSnackBar.getView();
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams)view.getLayoutParams();
params.gravity = Gravity.BOTTOM;
params.setMargins(0, 0, 0, 150);
view.setLayoutParams(params);
Instead of programmatically manipulating CoordinatorLayout parameters, I found that you can place a GuideLine (or a View, if you are not using ConstraintLayout) above which the Snackbar may be placed.我发现您可以放置一个 GuideLine(或一个视图,如果您不使用 ConstraintLayout),而不是以编程方式操作 CoordinatorLayout 参数,Snackbar 可以放置在其上方。 I'm using 1 here to indicate 100% meaning the bottom of the parent ConstraintLayout:
我在这里使用 1 来表示 100% 表示父 ConstraintLayout 的底部:
<androidx.constraintlayout.widget.Guideline
android:id="@+id/snackbar_anchor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="1" />
Use Viewbinding + this code to place the snackbar above the Guide:使用 Viewbinding + 此代码将小吃栏放置在指南上方:
Snackbar
.make(containerView, alert.description, Snackbar.LENGTH_LONG).apply {
anchorView = binding?.snackbarAnchor
show()
}
For any of you that cannot use the CoordinatorLayout
, even with the Anchor
solution such as it seems in my case对于无法使用
CoordinatorLayout
任何人,即使使用Anchor
解决方案,例如在我的情况下
It might be helpful to know you can add a listener to the Snackbar
and at most (if not all) views can add layout_marginBottom
at Runtime.知道您可以向
Snackbar
添加侦听器并且最多(如果不是全部)视图可以在运行时添加layout_marginBottom
可能会有所帮助。
From my initial testing, it seems to be working quite well.从我最初的测试来看,它似乎工作得很好。
following is my code, hopes it will help anyone以下是我的代码,希望它能帮助任何人
public class ItemActivity extends AppCompatActivity {
private ConstraintLayout mBottomViewConstraintLayout;
private int mPrevBottomPadding = 0;
private Snackbar mSnackbar;
private Snackbar.Callback mCallback = new Snackbar.Callback() {
@Override
public void onShown(Snackbar sb) {
super.onShown( sb );
addMarginToBottomView();
}
@Override
public void onDismissed(Snackbar transientBottomBar, int event) {
super.onDismissed( transientBottomBar, event );
initMarginToBottomView();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
//.....
mSnackbar = Snackbar.make(
findViewById( android.R.id.content ),
getString( R.string.snackbar_message_undo_item_removed ),
Snackbar.LENGTH_LONG)
.setAction( getString( R.string.snackbar_action_undo ),
new View.OnClickListener() {
@Override
public void onClick(View v) {
mItemDao.undoDelete( );
}
} )
.addCallback( mCallback )
.setDuration( Constants.SNACKBAR_DURATION_MS );
}
private void addMarginToBottomView() {
ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) mBottomViewConstraintLayout.getLayoutParams();
mPrevBottomPadding = layoutParams.bottomMargin;
layoutParams.bottomMargin += mSnackbar.getView().getHeight();
mBottomViewConstraintLayout.setLayoutParams(layoutParams);
}
private void initMarginToBottomView() {
ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) mBottomViewConstraintLayout.getLayoutParams();
layoutParams.bottomMargin = mPrevBottomPadding;
mBottomViewConstraintLayout.setLayoutParams(layoutParams);
}
private void showSnackbar() {
mSnackbar.show();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.