【问题标题】:Can we perform 2 different actions in Snack bar at a time in android?我们可以在 android 中一次在 Snack bar 中执行 2 个不同的操作吗?
【发布时间】:2017-05-04 14:08:25
【问题描述】:

我正在创建一个我想在其中使用 Snack Bar 的 android 应用程序, 在那个小吃店里,我想要 2 个不同的词,我们必须对它们执行 2 个不同的操作。

【问题讨论】:

  • 我认为小吃店不可能。你为什么不创建一个自定义小部件。
  • 也许你可以尝试反射......但这不是一个容易的恕我直言
  • 你已经完成了一些代码,请分享。

标签: android android-snackbar snackbar


【解决方案1】:

来自Google design specifications:

每个snackbar 可能包含一个动作,其中都不是“Dismiss”或“Cancel”。

对于多个操作,请使用对话框。

【讨论】:

  • 另外,here 你可以发现 SnakBar 类只有一个方法setAction()。没有像 addAction() 这样你不能添加 2 个动作。
  • 是否可以在列表视图的项目点击时打开对话框?
  • @AnjaliPatel 当然!在您的列表视图的 setOnItemClickListener 上设置一个回调,并在您的 onItemClick 实现中显示您的对话框
  • 我找到了。非常感谢您以正确的方式指导我:) @EliasN
  • 您可以通过添加自定义布局并实现对它们的点击来执行多个操作。
【解决方案2】:

感谢 Shailesh,我必须修改代码才能使其适合我。

my_snackbar.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:id="@+id/my_snackbar_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/dark_grey"
    android:padding="15dp">

    <TextView
        android:id="@+id/message_text_view"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight=".6"
        android:gravity="center_vertical"
        android:text="Two button snackbar"
        android:textColor="@color/white"/>

    <TextView
        android:id="@+id/first_text_view"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight=".2"
        android:gravity="center"
        android:text="ONE"
        android:textColor="#FFDEAD"/>

    <TextView
        android:id="@+id/second_text_view"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight=".2"
        android:gravity="center"
        android:text="TWO"
        android:textColor="#FFDEAD"/>

</LinearLayout> 

在您的活动中,只要您想显示小吃栏,就调用此方法:

 private void showTwoButtonSnackbar() {

    // Create the Snackbar
    LinearLayout.LayoutParams objLayoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    snackbar = Snackbar.make(this.findViewById(android.R.id.content), message, Snackbar.LENGTH_INDEFINITE);

    // Get the Snackbar layout view
    Snackbar.SnackbarLayout layout = (Snackbar.SnackbarLayout) snackbar.getView();

    // Set snackbar layout params
    int navbarHeight = getNavBarHeight(this);
    FrameLayout.LayoutParams parentParams = (FrameLayout.LayoutParams) layout.getLayoutParams();
    parentParams.setMargins(0, 0, 0, 0 - navbarHeight + 50);
    layout.setLayoutParams(parentParams);
    layout.setPadding(0, 0, 0, 0);
    layout.setLayoutParams(parentParams);

    // Inflate our custom view
    View snackView = getLayoutInflater().inflate(R.layout.my_snackbar, null);

    // Configure our custom view
    TextView messageTextView = (TextView) snackView.findViewById(R.id.message_text_view);
    messageTextView.setText(message);

    TextView textViewOne = (TextView) snackView.findViewById(R.id.first_text_view);
    textViewOne.setText("ALLOW");
    textViewOne.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.d("Allow", "showTwoButtonSnackbar() : allow clicked");
            snackbar.dismiss();
        }
    });

    TextView textViewTwo = (TextView) snackView.findViewById(R.id.second_text_view);
    textViewTwo.setText("DENY");
    textViewTwo.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.d("Deny", "showTwoButtonSnackbar() : deny clicked");
            snackbar.dismiss();
        }
    });

    // Add our custom view to the Snackbar's layout
    layout.addView(snackView, objLayoutParams);

    // Show the Snackbar
    snackbar.show();
}

获取导航栏高度:

public static int getNavBarHeight(Context context) {
    int result = 0;
    int resourceId = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
    if (resourceId > 0) {
        result = context.getResources().getDimensionPixelSize(resourceId);
    }
    return result;
} 

【讨论】:

  • 它有效,唯一缺少的是你不能通过向右滑动来关闭小吃店
【解决方案3】:

作为@Elias N 的答案,每个Snackbar 可能包含一个动作。如果您想在Snackbar 中设置更多操作,那么您需要创建自己的布局。请试试这个,希望对你有帮助。

创建一个xml文件my_snackbar.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="horizontal"
              android:layout_width="match_parent"
              android:layout_height="50dp"
              android:background="#000000">
    <TextView
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:layout_weight=".7"
        android:gravity="center_vertical"
        android:text="Please select any one"
        android:textColor="@color/white"/>

    <TextView
        android:id="@+id/txtOne"
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:layout_weight=".1"
        android:gravity="center"
        android:text="ONE"
        android:textColor="@color/red"/>
    <TextView
        android:id="@+id/txtTwo"
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:layout_weight=".1"
        android:gravity="center"
        android:text="TWO"
        android:textColor="@color/red"/>
</LinearLayout>

现在在您的活动文件中执行以下代码。

public void myCustomSnackbar()
{
    // Create the Snackbar
    LinearLayout.LayoutParams objLayoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    Snackbar snackbar = Snackbar.make(llShow, "", Snackbar.LENGTH_LONG);
    // Get the Snackbar's layout view
    Snackbar.SnackbarLayout layout = (Snackbar.SnackbarLayout) snackbar.getView();
    layout.setPadding(0,0,0,0);
    // Hide the text
    TextView textView = (TextView) layout.findViewById(android.support.design.R.id.snackbar_text);
    textView.setVisibility(View.INVISIBLE);

    LayoutInflater mInflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
    // Inflate our custom view
    View snackView = getLayoutInflater().inflate(R.layout.my_snackbar, null);
    // Configure the view
    TextView textViewOne = (TextView) snackView.findViewById(R.id.txtOne);

    textViewOne.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.i("One", "First one is clicked");
        }
    });

    TextView textViewTwo = (TextView) snackView.findViewById(R.id.txtTwo);
    textViewTwo.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
        Log.i("Two", "Second one is clicked");
        }
    });

    // Add the view to the Snackbar's layout
    layout.addView(snackView, objLayoutParams);
    // Show the Snackbar
    snackbar.show();
}

更多详情请阅读this documentation和here。

【讨论】:

  • 它在我的情况下不起作用,顺便说一句谢谢@Shailesh 如果您知道如何在单击 Listview 的 ltem 时打开对话框
  • 我的代码有什么问题?当我们单击列表视图中的项目时打开一个对话框。请参阅stackoverflow.com/questions/12470507/…。如果要设置自定义视图,则使用setView() 方法。
【解决方案4】:

您可以使用BottomSheetDialog 并将其伪装成SnackBar。唯一的区别是它将通过向下滑动而不是向右滑动来解除它,并且它可以一直呆在那里直到用户解除它,而 SnackBar 最终消失。

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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/fragment_history_menu_bottom"
    style="@style/Widget.Design.BottomNavigationView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:orientation="horizontal"
    android:background="@color/cardview_dark_background"
    app:layout_behavior="android.support.design.widget.BottomSheetBehavior">


    <android.support.v7.widget.AppCompatTextView
        android:id="@+id/appCompatTextView"
        android:layout_width="wrap_content"
        android:layout_height="19dp"
        android:layout_gravity="center_vertical"

        android:layout_marginStart="8dp"
        android:layout_weight="0.6"
        android:text="Load More ?"
        android:textAppearance="@style/TextAppearance.Design.Snackbar.Message"
        android:textColor="@color/cardview_light_background"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <LinearLayout
        android:id="@+id/fragment_history_bottom_sheet_delete"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right|end"
        android:layout_weight="0.4"
        android:clickable="true"
        android:focusable="true"
        android:foreground="?android:attr/selectableItemBackground"
        android:orientation="horizontal"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent">

        <android.support.v7.widget.AppCompatButton
            style="@style/Widget.AppCompat.Button.Borderless.Colored"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Yes" />

        <android.support.v7.widget.AppCompatButton
            style="@style/Widget.AppCompat.Button.Borderless"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="No"
            android:textColor="@color/cardview_light_background" />
    </LinearLayout>
</android.support.constraint.ConstraintLayout>

并按照以下方式使用它(Kotlin)

val dialog = BottomSheetDialog(this)
    dialog.setContentView(this.layoutInflater.inflate(R.layout.bottom_sheet_load_prompt,null))
    dialog.show()

结果将类似于 SnackBar

【讨论】:

  • 如何处理点击?
  • @akshaybhange 你可以这样做 val dialog = BottomSheetDialog(context) dialog.setContentView(this.layoutInflater.inflate(R.layout.bottom_sheet_load_prompt, null)) dialog.load_affirmation.setOnClickListener { } dialog .load_negetation.setOnClickListener { loadingBlocked = true; dialog.dismiss() } 来源:github.com/jatindhankhar/wlosh/blob/master/app/src/main/java/in/…
【解决方案5】:

这是一个带有 Kotlin 的 proper solution,我在处理 Fulguris 时首次部署它。

使用 Kotlin 扩展,我们将 Snackbar 类扩展如下:

/**
* Adds an extra action button to this snackbar.
* [aLayoutId] must be a layout with a Button as root element.
* [aLabel] defines new button label string.
* [aListener] handles our new button click event.
*/
fun Snackbar.addAction(@LayoutRes aLayoutId: Int, @StringRes aLabel: Int, aListener: View.OnClickListener?) : Snackbar {
    addAction(aLayoutId,context.getString(aLabel),aListener)
    return this;
}

/**
* Adds an extra action button to this snackbar.
* [aLayoutId] must be a layout with a Button as root element.
* [aLabel] defines new button label string.
* [aListener] handles our new button click event.
*/
fun Snackbar.addAction(@LayoutRes aLayoutId: Int, aLabel: String, aListener: View.OnClickListener?) : Snackbar {
    // Add our button
    val button = LayoutInflater.from(view.context).inflate(aLayoutId, null) as Button
    // Using our special knowledge of the snackbar action button id we can hook our extra button next to it
    view.findViewById<Button>(R.id.snackbar_action).let {
        // Copy layout
        button.layoutParams = it.layoutParams
        // Copy colors
        (button as? Button)?.setTextColor(it.textColors)
        (it.parent as? ViewGroup)?.addView(button)
    }
    button.text = aLabel
    /** Ideally we should use [Snackbar.dispatchDismiss] instead of [Snackbar.dismiss] though that should do for now */
    //extraView.setOnClickListener {this.dispatchDismiss(BaseCallback.DISMISS_EVENT_ACTION); aListener?.onClick(it)}
    button.setOnClickListener {this.dismiss(); aListener?.onClick(it)}
    return this;
}

然后我们需要定义我们的按钮资源:

<?xml version="1.0" encoding="utf-8"?>
<!--
Used to create and extra button in our snackbar popup messages.
Though most properties including layout params and colors are overridden at runtime.
They are just copied from the standard snackbar action button to make sure they both lookalike.
-->
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/snackbar_extra_action"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="0dp"
android:layout_marginStart="0dp"
android:layout_gravity="center_vertical|right|end"
android:paddingTop="14dp"
android:paddingBottom="14dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:textColor="?attr/colorAccent"
style="?attr/borderlessButtonStyle"/>

这是你如何使用它:

Snackbar.make(aView, aMessage, aDuration).setAction(R.string.button_one) {
    // Do your thing after regular button press
}.addAction(R.layout.snackbar_extra_button, R.string.button_two){
    //Do your thing after extra button push
        }.show()

【讨论】:

    【解决方案6】:

    您可以尝试另一种 hacky 解决方法(在我的情况下有效)。

        final Snackbar snackbar = Snackbar.make(view, "UNDO MARKED AS READ", Snackbar.LENGTH_LONG);
        snackbar.setAction("DISMISS", new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (snackbar != null)
                    snackbar.dismiss();
            }
        });
        View snackbarView = snackbar.getView();
        int snackbarTextId = android.support.design.R.id.snackbar_text;
        TextView textView = (TextView) snackbarView.findViewById(snackbarTextId);
        textView.setTextColor(Color.WHITE);
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (snackbar != null)
                    snackbar.dismiss();
                // undo mark as unread code
            }
        });
        snackbar.show();
    

    【讨论】:

      【解决方案7】:

      遵循 Shaileshs 解决方案:

      小吃店类

      public class SnackbarOfflineErrorNotification {
      /**
       * A view from the content layout.
       */
      @NonNull
      private final View view;
      
      @NonNull
      private Context context;
      
      /**
       * The snack bar being shown.
       */
      @Nullable
      private Snackbar snackbar = null;
      
      /**
       * Construct a new instance of the notification.
       *
       * @param view A view from the content layout, used to seek an appropriate anchor for the
       *             Snackbar.
       */
      public SnackbarOfflineErrorNotification(@NonNull final View view, @NonNull Context context) {
          this.view = view;
          this.context = context;
      }
      
      public void showOfflineError (){
          if (snackbar == null){
              //create snackbar
              snackbar = Snackbar.make(this.view, R.string.offline_text, LENGTH_INDEFINITE);
      
              // Create the Snackbar
              LinearLayout.LayoutParams objLayoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
      
              // Get the Snackbar's layout view
              Snackbar.SnackbarLayout layout = (Snackbar.SnackbarLayout) snackbar.getView();
              layout.setPadding(0,0,0,0);
              // Hide the text
              TextView textView = (TextView) layout.findViewById(android.support.design.R.id.snackbar_text);
              textView.setVisibility(View.INVISIBLE);
      
              // Inflate our custom view
              LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
              View snackView = inflater.inflate(R.layout.snackbar_offline, null);
              // Configure the view
              Button btnOne = (Button) snackView.findViewById(R.id.btnOne);
      
              btnOne.setOnClickListener(new View.OnClickListener() {
                  @Override
                  public void onClick(View v) {
                      // action 1
                  }
              });
      
              Button btnTwo = (Button) snackView.findViewById(R.id.btnTwo);
              btnTwo.setOnClickListener(new View.OnClickListener() {
                  @Override
                  public void onClick(View v) {
                      // action 2
                  }
              });
      
              // Add the view to the Snackbar's layout
              layout.addView(snackView, objLayoutParams);
      
              // Show the Snackbar
              snackbar.show();
          }
      
      }
      
      /**
       * Hides the currently displayed error.
       */
      public void hideError() {
          if (snackbar != null) {
              snackbar.dismiss();
              snackbar = null;
          }
      }
      }
      

      小吃吧 xml

      <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:orientation="horizontal"
      android:layout_width="match_parent"
      android:layout_height="50dp"
      android:background="#000000">
      
      <TextView
          android:layout_width="wrap_content"
          android:layout_height="50dp"
          android:layout_weight=".7"
          android:gravity="center_vertical"
          android:text="offline"
          android:textColor="@color/white"
          android:paddingLeft="16dp"/>
      
      <Button
          android:id="@+id/btnOne"
          android:layout_width="wrap_content"
          android:layout_height="50dp"
          android:layout_weight=".1"
          android:gravity="center"
          android:text="one" />
      
      <Button
          android:id="@+id/btnTwo"
          android:layout_width="wrap_content"
          android:layout_height="50dp"
          android:layout_weight=".1"
          android:gravity="center"
          android:text="two"/>
      </LinearLayout>
      

      目标活动

      constructor(){
          snackbarOfflineErrorNotification = new SnackbarOfflineErrorNotification(findViewById(R.id.coordinator_layout), getApplicationContext());
      }
      
      public void hideSnackbar(){
          snackbarOfflineErrorNotification.hideError();
      }
      
      public showSnackbar(){
          snackbarOfflineErrorNotification.showOfflineError();
      }
      

      【讨论】:

      • 您可以为您的解决方案添加解释吗?尤其是它与 Shailesh 的答案有何不同,即它增加或改进了什么。谢谢!
      【解决方案8】:

      您可以将“解雇”用作其他操作

              Snackbar snackbar = Snackbar.make(requireView(), "Marked as read", BaseTransientBottomBar.LENGTH_SHORT);
              snackbar.setAction("undo", view -> {
                  //undo action
              });
              snackbar.addCallback(new Snackbar.Callback() {
                  @Override
                  public void onDismissed(Snackbar transientBottomBar, int event) {
                     //dismiss action
                  }
              });
              snackbar.show();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-23
        • 1970-01-01
        • 2016-06-29
        • 1970-01-01
        • 2021-09-07
        • 2022-08-16
        • 2018-07-24
        • 2022-10-13
        相关资源
        最近更新 更多