【问题标题】:Make Snackbar push view upwards使 Snackbar 向上推视图
【发布时间】:2016-02-16 01:12:48
【问题描述】:

有没有办法让snackbar在显示时将视图向上推?

目前,当显示快餐栏时,它会覆盖下面的视图,因此看起来按钮的一半被切断了,但我希望它几乎是“adjustPan”,类似于软键盘在屏幕上显示时的工作方式.

有谁知道实现这一点的任何技巧吗?

【问题讨论】:

    标签: android snackbar


    【解决方案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_width="match_parent"
          android:layout_height="match_parent">
          <TextView
          android:text="s"
          android:layout_weight="1"
          android:layout_width="match_parent"
          android:layout_height="wrap_content" />
          <android.support.design.widget.CoordinatorLayout
              android:layout_width="match_parent"
              android:layout_marginBottom="200dp"
              android:layout_height="100dp">
              <TextView
                  android:id="@+id/tv_main"
                  android:background="#4b14b1"
                  android:layout_width="100dp"
                  android:layout_height="100dp" />
          </android.support.design.widget.CoordinatorLayout>
      </RelativeLayout>
      

      【讨论】:

        【解决方案4】:

        将您的视图放入 android.support.design.CoordinatorLayout

        <android.support.design.widget.CoordinatorLayout
            android:id="@+id/coordinator"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true">
        
            <View
                android:id="@+id/my_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                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 - 子视图。 (在快餐栏或其他依赖项的情况下必须移动的视图)
        猜你喜欢
        • 2015-10-09
        • 2015-12-25
        • 1970-01-01
        • 2020-03-08
        • 1970-01-01
        • 1970-01-01
        • 2020-06-24
        • 1970-01-01
        • 2017-04-10
        相关资源
        最近更新 更多