使 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 会感觉有点“有弹性”。但是如果我使用其他东西,比如ConstraintLayoutFloatingActionButtonBehavior,那么“有弹性”的感觉就不存在了; 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 会找到最近的 CoordinatorLayoutparentView

 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 其中 T - 子视图。 (在快餐栏或其他依赖项的情况下必须移动的视图)

以上是关于使 Snackbar 向上推视图的主要内容,如果未能解决你的问题,请参考以下文章

Snackbar getAnchorView() 与父视图

android中的全局SnackBar

使用可下载字体作为自定义 Snackbar 字体

关闭 Snackbar 时,FloatingActionButton 不会出现

如何使 Snackbar 在类组件中工作?

当 SnackBar 出现在 CoordinatorLayout 中时上移视图