使 Snackbar 向上推视图
Posted
技术标签:
【中文标题】使 Snackbar 向上推视图【英文标题】:Make Snackbar push view upwards 【发布时间】:2016-02-16 01:12:48 【问题描述】:有没有办法让snackbar在显示时将视图向上推?
目前,当显示快餐栏时,它会覆盖下面的视图,因此看起来按钮的一半被切断了,但我希望它几乎是“adjustPan”,类似于软键盘在屏幕上显示时的工作方式.
有谁知道实现这一点的任何技巧吗?
【问题讨论】:
【参考方案1】:简短回答:如果您只想在 Snackbar 出现时将视图向上推,只需将以下行添加到您的视图中。无需再定义FloatingActionButtonBehavior
。
app:layout_dodgeInsetEdges="bottom"
长答案:接受的答案中描述的FloatingActionButtonBehavior
肯定可以完成工作。
我注意到的一件事是,如果我有一个 CoordinatorLayout
和一个真正的 FloatingActionButton
而没有 FloatingActionButtonBehavior
,那么当 Snackbar 出现时,FAB 会感觉有点“有弹性”。但是如果我使用其他东西,比如ConstraintLayout
和FloatingActionButtonBehavior
,那么“有弹性”的感觉就不存在了; Snackbar 上方的 View 只是在底部显示了足够的空间供 Snackbar 使用,而 Snackbar 逐渐填满空间。这是相当微妙的,我相信大多数人甚至都没有注意到它,也没有在意它。
这是 Snackbar 开始出现的时候。请注意,它的大小略小于其完整大小。
几分之一秒后,Snackbar“扩大”到它的全尺寸。
这就是“有弹性”的感觉; FAB 的位置基于 Snackbar 的当前大小,而不是 Snackbar 完全显示的大小。
要复制此行为,只需让FloatingActionButtonBehavior
知道将 FAB 锚定在哪里,而不是自己计算 Y 坐标。更好的是,请参阅“简答”。
/*
Replicate real FAB's behavior. Code shamelessly stolen from
com/google/android/material/floatingactionbutton/FloatingActionButton.java
*/
class FloatingActionButtonBehavior(
context: Context,
attrs: AttributeSet
) : CoordinatorLayout.Behavior<View>()
override fun onAttachedToLayoutParams(params: CoordinatorLayout.LayoutParams)
super.onAttachedToLayoutParams(params)
if (params.dodgeInsetEdges == Gravity.NO_GRAVITY)
params.dodgeInsetEdges = Gravity.BOTTOM
【讨论】:
app:layout_dodgeInsetEdges="bottom"
解决方案确实有效,感觉不像是 hack。必须将其放置在最上面的布局视图中,例如在 activity_main.xml
协调器布局中,用于一活动多片段应用程序。【参考方案2】:
他是在 Kotlin 中使用泛型的 SourceRebeles 解决方案。
typealias T = View
class FloatingActionButtonBehavior(context: Context, attrs: AttributeSet) : CoordinatorLayout.Behavior<T>()
override fun layoutDependsOn(parent: CoordinatorLayout, child: T, dependency: View): Boolean
return dependency is SnackbarLayout
override fun onDependentViewChanged(parent: CoordinatorLayout, child: T, dependency: View): Boolean
val translationY = Math.min(0.0f, (dependency.translationY - dependency.height).toFloat())
child.translationY = translationY
return true
【讨论】:
【参考方案3】:Snackbar 会找到最近的 CoordinatorLayout
和 parentView
;
findViewById(R.id.tv_main).setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View view)
Snackbar.make(findViewById(R.id.tv_main), "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
toolbar.getChildAt(1).setVisibility(View.GONE);
);
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_
android:layout_>
<TextView
android:text="s"
android:layout_weight="1"
android:layout_
android:layout_ />
<android.support.design.widget.CoordinatorLayout
android:layout_
android:layout_marginBottom="200dp"
android:layout_>
<TextView
android:id="@+id/tv_main"
android:background="#4b14b1"
android:layout_
android:layout_ />
</android.support.design.widget.CoordinatorLayout>
</RelativeLayout>
【讨论】:
【参考方案4】:将您的视图放入 android.support.design.CoordinatorLayout
<android.support.design.widget.CoordinatorLayout
android:id="@+id/coordinator"
android:layout_
android:layout_
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true">
<View
android:id="@+id/my_view"
android:layout_
android:layout_
app:layout_behavior="com.example.FloatingActionButtonBehavior"/>
</android.support.design.widget.CoordinatorLayout>
这里的重要部分是 app:layout_behavior 属性。这是实现类:
public class FloatingActionButtonBehavior extends CoordinatorLayout.Behavior<FloatingActionButton>
public FloatingActionButtonBehavior(Context context, AttributeSet attrs)
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency)
return dependency instanceof SnackbarLayout;
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child, View dependency)
float translationY = Math.min(0, dependency.getTranslationY() - dependency.getHeight());
child.setTranslationY(translationY);
return true;
然后,当您显示快餐栏时,将引用传递给 CoordinatorLayout:
CoordinatorLayout coordinator = findViewById(R.id.coordinator);
Snackbar.make(coordinator, textResId, Snackbar.LENGTH_LONG)
.setAction(R.string.accept_ok, new View.OnClickListener()
@Override
public void onClick(View v)
)
.setDuration(Snackbar.LENGTH_INDEFINITE)
.show();
希望这会对你有所帮助。
【讨论】:
谢谢 - 但我在我的 coordinatorlayout 中使用 viewGroup (LinearLayout) 而不是视图。无论如何在您的代码中使用视图组?我尝试使用linearLayout,但它给了我一个错误提示:android.widget.LinearLayout cannot be cast to android.support.design.widget.FloatingActionButton 我使用这个解决方案来推动我的 relativeLayout,就像一个魅力 :) @Simon 您是否忘记在两个覆盖方法中也将 FloatingActionButton 更改为 LinearLayout? 我只想指出,即使空的构造函数看起来没什么用,但如果你不声明它,你会在设计视图中的布局预览时得到一个异常。 使用此解决方案,如果您使用滑动关闭快餐栏功能,您的布局将保持在新位置。要返回旧位置,您可以使用snackbar.setCallback(new Snackbar.Callback() @Override public void onDismissed(Snackbar snackbar, int event) super.onDismissed(snackbar, event); yourLayout.setTranslationY(0.0f); );
我想补充一点,您需要创建自定义 Bahavior。所以,一般来说,它看起来像 CoordinatorLayout.Behavior以上是关于使 Snackbar 向上推视图的主要内容,如果未能解决你的问题,请参考以下文章