【问题标题】:How to disable BottomSheetDialogFragment dragging如何禁用 BottomSheetDialogFragment 拖动
【发布时间】:2017-10-21 08:04:27
【问题描述】:

如何禁用BottomSheetDialogFragment手指拖动?

我看到了类似的问题,但都是关于BottomSheet 而不是BottomSheetDialogFragment

【问题讨论】:

标签: android android-layout android-view android-dialog bottom-sheet


【解决方案1】:

已创建MyActivity,如下:

public class MyActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);

        new MyBottomSheetFragment().show(getSupportFragmentManager(), "tag");
    }

    public static class MyBottomSheetFragment extends BottomSheetDialogFragment {

        @Override
        public void setupDialog(Dialog dialog, int style) {
            BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) dialog;
            bottomSheetDialog.setContentView(R.layout.sample);

            try {
                Field behaviorField = bottomSheetDialog.getClass().getDeclaredField("behavior");
                behaviorField.setAccessible(true);
                final BottomSheetBehavior behavior = (BottomSheetBehavior) behaviorField.get(bottomSheetDialog);
                behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {

                    @Override
                    public void onStateChanged(@NonNull View bottomSheet, int newState) {
                        if (newState == BottomSheetBehavior.STATE_DRAGGING{ 
                            behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
                        }
                    }

                    @Override
                    public void onSlide(@NonNull View bottomSheet, float slideOffset) {
                    }
                });
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
}

R.layout.sample 是一个简单的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <View
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="#e479da" />

    <View
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="#798de4" />

    <View
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="#e4db79" />

</LinearLayout>

你会得到以下输出:

部分解法借自this答案。

【讨论】:

  • 这是很好的示例代码,但存在一些问题。首先, setupDialog 不是 BottomSheetDialogFragment 方法。其次,我的底部工作表视图中有一个回收站视图,当我从 recyclerView 的空白处拖动底部工作表时,底部工作表会向下滑动。
  • setupDialog() 是来自 DialogFragment 类的方法。已将其替换为 onCreateDialog()。无法理解您的用例。你能在 github 上发布一个具有这种行为的简单项目吗?
  • 它在我的片段中收到警告:java.lang.NoSuchFieldException: No field mBehavior in class Landroid/support/design/widget/BottomSheetDialog; ('android.support.design.widget.BottomSheetDialog' 的声明) System.err: at java.lang.Class.getDeclaredField(Native Method)
  • 字段名是behavior,不是mBehavior。这就是您收到该错误的原因。
  • 谢谢@MarcoCarrizales,将答案从mBehavior 更新为behavior
【解决方案2】:

Material Design 1.2.0 发布后有更简单的方法来实现。

https://developer.android.com/reference/com/google/android/material/bottomsheet/BottomSheetBehavior#setdraggable

当从BottomSheetDialogFragment调用时:

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val bottomSheetDialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog
        bottomSheetDialog.setOnShowListener {
            val bottomSheet = bottomSheetDialog
                .findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet)

            if (bottomSheet != null) {
                val behavior: BottomSheetBehavior<*> = BottomSheetBehavior.from(bottomSheet)
                behavior.isDraggable = false
            }
        }
        return bottomSheetDialog
    }

或者带有样式:

    <style name="SomeStyle" parent="Theme.MaterialComponents.Light.BottomSheetDialog">
        <item name="behavior_draggable">false</item>
    </style>

然后在对话片段的onCreate 中:

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setStyle(DialogFragment.STYLE_NORMAL, R.style.SomeStyle)
    }

【讨论】:

  • 这是正确答案,应该有更多的赞成票!
  • 使用样式比其他答案要好得多。谢谢!
【解决方案3】:

为时已晚,但值得分享。

  behavior.setDraggable(false)

这条线完成了这项工作。

【讨论】:

  • 什么类有isDraggable?
  • final BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet); stackoverflow.com/questions/35618998/…
  • @AndreyUglev 它来自BottomSheetDialog.behavior
  • 这是正确答案。此方法已添加到新版本的材料库中。我正在使用 com.google.android.material:material:1.3.0 并且我有 setDraggable() 方法。我在1.1.0 版本时没有该方法。它也在文档中...developer.android.com/reference/com/google/android/material/…
  • 还不算太晚,完美的时机:)
【解决方案4】:

如果要禁用BottomSheetDialog拖动,请尝试设置setCancelable(false)

【讨论】:

  • 它适用于我的情况,只是有一个问题,在将可取消设置为 false 后单击外部字段将被禁用。谢谢。 +1
  • 最简单最优雅。
【解决方案5】:

我的版本。它完美地工作。

编辑 09/04/2020: 将已折旧的 setBottomSheetCallback() 替换为 addBottomSheetCallback()

class FragMenuBDrawer : BottomSheetDialogFragment() {

    ...

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog

        dialog.setOnShowListener {
            val bottomSheet = (it as BottomSheetDialog).findViewById<View>(com.google.android.material.R.id.design_bottom_sheet) as FrameLayout?
            val behavior = BottomSheetBehavior.from(bottomSheet!!)
            behavior.state = BottomSheetBehavior.STATE_EXPANDED

            behavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
                override fun onStateChanged(bottomSheet: View, newState: Int) {
                    if (newState == BottomSheetBehavior.STATE_DRAGGING) {
                        behavior.state = BottomSheetBehavior.STATE_EXPANDED
                    }
                }

                override fun onSlide(bottomSheet: View, slideOffset: Float) {}
            })
        }

        // Do something with your dialog like setContentView() or whatever
        return dialog
    }

    ...
}

【讨论】:

    【解决方案6】:
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
        //Disable dragging by set isDraggable to false
        val bottomSheetDialog = dialog as BottomSheetDialog
        val bottomSheetBehavior = bottomSheetDialog.behavior
        bottomSheetBehavior.isDraggable = false
    }
    

    【讨论】:

    • 在 Kotlin 中是可拖动的。如果你使用 Java 使用 setDraggable(boolean draggable)
    【解决方案7】:

    这是 azizbekian's 答案的 Kotlin 版本,因为有人询问使用数据绑定

    @SuppressLint("RestrictedApi")
    override fun setupDialog(d: Dialog?, style: Int) {
        super.setupDialog(d, style)
        dialogExampleBinding = DataBindingUtil
            .inflate(LayoutInflater.from(context), R.layout.dialogExample, null, false) //This is for data binding only
        d?.setContentView(R.layout.dialogExample)
    
        val myDialog:BottomSheetDialog = d as BottomSheetDialog
        val dField = myDialog.javaClass.getDeclaredField("behavior") //This is the correct name of the variable in the BottomSheetDialog class
        dField.isAccessible = true
        val behavior = dField.get(d) as BottomSheetBehavior<*>
        behavior.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
            override fun onStateChanged(bottomSheet: View, newState: Int) {
                if (newState == BottomSheetBehavior.STATE_DRAGGING) {
                    behavior.state = BottomSheetBehavior.STATE_EXPANDED
                }
            }
    
            override fun onSlide(bottomSheet: View, slideOffset: Float) {}
        })
    }
    

    【讨论】:

      【解决方案8】:

      只需添加 bottomSheetBehavior.setHideable(false);

      您可以在BottomSheetDialogFragment 中获取BottomSheetBehaviour 的对象。

       CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) ((View) view.getParent()).getLayoutParams();
                  CoordinatorLayout.Behavior behavior = params.getBehavior();
                  View parent = (View) view.getParent();
                  getHeight(view);
                  ((BottomSheetBehavior) behavior).setFitToContents(true);
                  BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(parent);
      bottomSheetBehavior.setHideable(false);
      

      【讨论】:

      • 我们如何获得bottomSheetBehavior对象?
      • 请查看答案
      【解决方案9】:

      这就是我设法修复它的方法:

      mBehavior = BottomSheetBehavior.from((View) rootView.getParent());
      mBehavior.setHideable(false);
      

      【讨论】:

        【解决方案10】:

        评分最高的答案包含样板代码,例如 Field 和 try-catch。

        所以这里有一个更好的 Kotlin 版本:

        override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
            return super.onCreateDialog(savedInstanceState).apply {
                setOnShowListener(::onShow)
            }
        }
        
        private fun onShow(dialogInterface: DialogInterface) {
            val dialog = dialogInterface as BottomSheetDialog
            val frameLayout =
                dialog.findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet)
                    ?: return
        
            BottomSheetBehavior.from(frameLayout).apply {
                addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
                    override fun onStateChanged(bottomSheet: View, newState: Int) {
                        if (newState == BottomSheetBehavior.STATE_DRAGGING)
                            state = BottomSheetBehavior.STATE_EXPANDED
                    }
        
                    override fun onSlide(bottomSheet: View, slideOffset: Float) = Unit
                })
            }
        }
        

        BottomSheetDialogFragment使用它

        【讨论】:

          【解决方案11】:

          这对我有用,先生

          override fun onCreateDialog(savedInstanceState : Bundle?) : Dialog {
              val dialog = super.onCreateDialog(savedInstanceState);
              dialog.setOnShowListener {
                  val bottomSheetDialog : BottomSheetDialog = it as BottomSheetDialog;
                  var bottomSheetBehavior = BottomSheetBehavior<FrameLayout>();
                  bottomSheetBehavior = bottomSheetDialog.getBehavior()
                  bottomSheetBehavior.setDraggable(false);
              }
              return dialog }
          

          【讨论】:

            【解决方案12】:

            我得到了答案here,我刚刚添加了content.setLayoutParams(new CoordinatorLayout.LayoutParams(CoordinatorLayout.LayoutParams.MATCH_PARENT, CoordinatorLayout.LayoutParams.MATCH_PARENT)); 以使底部工作表对话框片段高度为 match_parent 并使其在显示时变软。

            @NonNull
            @Override
            public Dialog onCreateDialog(Bundle savedInstanceState) {
                final Dialog d = super.onCreateDialog(savedInstanceState);
                // view hierarchy is inflated after dialog is shown
                d.setOnShowListener(new DialogInterface.OnShowListener() {
                    @Override
                    public void onShow(DialogInterface dialogInterface) {
                        //this disables outside touch
                        d.getWindow().findViewById(R.id.touch_outside).setOnClickListener(null);
                        //this prevents dragging behavior
                        View content = d.getWindow().findViewById(R.id.design_bottom_sheet);
                        content.setLayoutParams(new CoordinatorLayout.LayoutParams(CoordinatorLayout.LayoutParams.MATCH_PARENT, CoordinatorLayout.LayoutParams.MATCH_PARENT));
                        ((CoordinatorLayout.LayoutParams) content.getLayoutParams()).setBehavior(null);
                    }
                });
                return d;
            }
            

            【讨论】:

              【解决方案13】:

              简单的解决方案

                  CoordinatorLayout.Behavior<View> behavior;
              
                  View profile_config_layout_bottom_sheet = findViewById(R.id.list_view_audience_profile_config_layout);
              
                  CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) profile_config_layout_bottom_sheet.getLayoutParams();
                  behavior = layoutParams.getBehavior();
                  assert behavior != null;
                  ((BottomSheetBehavior<View>) behavior).addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
                      @Override
                      public void onStateChanged(@NonNull View bottomSheet, int newState) {
                          if (newState == BottomSheetBehavior.STATE_DRAGGING) {
                              ((BottomSheetBehavior<View>) behavior).setState(BottomSheetBehavior.STATE_EXPANDED);
                          } 
                      }
                      @Override
                      public void onSlide(@NonNull View bottomSheet, float slideOffset) {}
                  });
              

              【讨论】:

                【解决方案14】:

                这是我的解决方案:

                setOnShowListener {
                            Handler().post {
                                val bottomSheet = findViewById<View>(R.id.design_bottom_sheet) as? FrameLayout
                                bottomSheet?.let {
                                    BottomSheetBehavior.from(it).state = STATE_EXPANDED
                
                                    // Disable dialog dragging behavior which causes issue on EditText scroll!
                                    BottomSheetBehavior.from(it).isDraggable = false
                                }
                
                            }
                        }
                

                【讨论】:

                  【解决方案15】:

                  我的简单解决方案:

                   override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
                      val dialog = BottomSheetDialog(requireContext(), R.style.DialogRoundedCornerStyle)
                      dialog.behavior.apply {
                          state = BottomSheetBehavior.STATE_EXPANDED
                          isDraggable = false
                      }
                      return dialog
                  }
                  

                  【讨论】:

                    【解决方案16】:

                    在你的oncreateView

                    //Kotlin
                    val baseDialog = dialog
                    if (baseDialog is BottomSheetDialog) {
                        baseDialog.behavior.isDraggable = false
                    }
                    //If cancelable also not required.
                    isCancelable = false
                    

                    【讨论】:

                      【解决方案17】:

                      他们也可以通过设置可拖动来做到这一点,所以这是我的另一个例子。

                      我的BottomSheetDialogFragment里面包含了一个RecyclerView,如果你需要一个BottomSheetDialogFragment禁止往上拖,可以往下拖,我做的就是把RecyclerView设置为绝对高度

                       <androidx.recyclerview.widget.RecyclerView
                              android:layout_width="match_parent"
                              android:layout_height="367dp"/>
                      

                      【讨论】:

                        【解决方案18】:

                        如果您只想禁用底部表的关闭,您可以简单地将 isCancelable false 设置为片段实例

                        val bSheet = BottomSheetFragment.newInstance("") bSheet.isCancelable = false bSheet.show(supportFragmentManager, "sheet")

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 1970-01-01
                          • 2015-04-24
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          相关资源
                          最近更新 更多