BottomSheetDialogFragment 在横向模式下不显示全高

Posted

技术标签:

【中文标题】BottomSheetDialogFragment 在横向模式下不显示全高【英文标题】:BottomSheetDialogFragment doesn't show full height in landscape mode 【发布时间】:2018-01-18 17:39:50 【问题描述】:

我在我的活动中使用 BottomSheetDialogFragment,对话框在纵向模式下显示全高,但在我切换到横向模式时不显示。

MainActivity.java

public class MainActivity extends AppCompatActivity 

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        CustomBottomSheetDialog customBottomSheetDialog = new CustomBottomSheetDialog();
        customBottomSheetDialog.show(getSupportFragmentManager(),customBottomSheetDialog.getTag());
    

CustomBottomSheetDialog

public class CustomBottomSheetDialog extends BottomSheetDialogFragment 

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) 
        return View.inflate(getContext(), R.layout.view_config, null);
    

CustomBottomSheetDialog 布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_
              android:background="#fdf107"
              android:layout_>

    <TextView
        android:layout_
        android:layout_
        android:gravity="center"
        android:textColor="@color/colorAccent"
        android:text="BottomSheetDialogFragment"/>

</LinearLayout>

在横向模式下,我必须拖动 BottomSheetDialogFragment 才能看到全部内容。

【问题讨论】:

原来这是预期的行为 (issuetracker.google.com/issues/37083487)。引用“Material Design 指南说,底页应该在底页上方区域为 19:6 的高度窥视。由于您的横向屏幕小于 16:9,因此它会窥视规范中的最小高度。 " @Bracadabra 我没有看到你所指的报价。 @clever_trevor 评论好像被删除了。 【参考方案1】:

这个问题的解决办法是。

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) 
    super.onViewCreated(view, savedInstanceState);
    view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() 
        @Override
        public void onGlobalLayout() 
            if (Build.VERSION.SDK_INT < 16) 
                view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
             else 
                view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            
            BottomSheetDialog dialog = (BottomSheetDialog) getDialog();
            FrameLayout bottomSheet = (FrameLayout)
            dialog.findViewById(android.support.design.R.id.design_bottom_sheet);
            BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
            behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
            behavior.setPeekHeight(0); // Remove this line to hide a dark background if you manually hide the dialog.
        
    );

【讨论】:

一旦事件被触发,别忘了注销监听器。 谢谢!我有这个问题:当对话框隐藏时,停电并没有消失。注释掉这一行对我有帮助:behavior.setPeekHeight(0); 哈克,但它有效。这是有风险的,因为它取决于android.support.design.R.id.design_bottom_sheet,Google 可以随时决定重命名它并导致代码损坏。还有其他方法可以通过原生 Android SDK 方法实现吗? @Ivan 如果他们在支持库中重命名代码,您的代码将无法编译。 如果你使用androidx库,你应该使用com.google.android.material.R.id.design_bottom_sheet【参考方案2】:

这对我有用,是最干净的方法:

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog 
    val dialog = BottomSheetDialog(requireContext(), theme)
    dialog.behavior.state = BottomSheetBehavior.STATE_EXPANDED
    return dialog

【讨论】:

如果你也发布一些解释会更有帮助,例如你为什么选择这种方法。请阅读***.com/help/how-to-answer 在最近的api中dialog.behavior没有暴露,是私有的 它是公开的。刚刚检查了一下:dialog.behavior.state 也可以将第二行替换为val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog 如果您在尝试关闭或隐藏对话框时处于折叠状态,请同时添加:dialog.behavior.skipCollapsed = true【参考方案3】:

感谢@avez raj 和Prevent dismissal of BottomSheetDialogFragment on touch outside 我写在onCreateDialog()

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

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

    return dialog

目前我使用MakinTosH解决方案,它更短。

【讨论】:

为什么会这样呢?在什么情况下会变成这样?有官方的处理方式吗?也许我们应该在它没有扩展时以不同的方式处理它?或者它是一个错误?我在 Play 商店也注意到了一个与之相关的奇怪错误:issuetracker.google.com/issues/133809189 @androiddeveloper,好问题,我不知道。 BSDF 是非常错误的观点。尤其是涉及到键盘的时候。感谢您的研究。 但即使没有键盘,它也被折叠成更小的尺寸 @androiddeveloper,我想,谷歌公司的他们每天都在制作奇怪的伙伴组件。程序员必须为每个错误创建解决方法。我的前同事也注意到 BSDF 在全屏键盘上的问题,甚至想用片段而不是 BSDF 重写。 @androiddeveloper,如果他更改代码,我可能会问他详细信息。【参考方案4】:

ViewTreeObserver 解决方案对我不起作用,但我找到了一个更好的解决方案 here 并将其转换为 Kotlin。这个没有 ViewTreeObserver 带来的昂贵的计算浪费,并且很好地将功能捆绑到类中。

class ExpandedBottomSheetDialog(context: Context) : BottomSheetDialog(context) 

    override fun show() 
        super.show()
        // androidx should use: com.google.android.material.R.id.design_bottom_sheet
        val view = findViewById<View>(R.id.design_bottom_sheet)
        view!!.post 
            val behavior = BottomSheetBehavior.from(view)
            behavior.setState(BottomSheetBehavior.STATE_EXPANDED)
        
    

【讨论】:

此解决方案不适用于 BottomSheetDialogFragment,因为它使用未附加到任何viewfindViewById(在此阶段为null)。此外,如果您覆盖show(manager: FragmentManager?, tag: String?)(请参阅***.com/questions/15729138/…)并使用super.show(manager, tag),那么您可能会捕获异常。【参考方案5】:

您可以简单地执行以下操作:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) 
    super.onViewCreated(view, savedInstanceState)
    dialog?.let 
        val sheet = it as BottomSheetDialog
        sheet.behavior.state = BottomSheetBehavior.STATE_EXPANDED
    

    // rest of your stuff

【讨论】:

【参考方案6】:

这是gestureInsetBottomIgnored的问题。对于横向,此标志为 false,但对于纵向,此标志为 true。

【讨论】:

【参考方案7】:

任何原因添加`onConfigurationChanged后,它不起作用(需要再次横向拖动它)

// support when screen rotate, resize etc.
override fun onConfigurationChanged(newConfig: Configuration) 
    super.onConfigurationChanged(newConfig)
    rvLayoutManager.spanCount = getSpanCount()
    rvLayoutManager.requestLayout()


private fun getSpanCount(): Int 
    val widthPx = resources.displayMetrics.widthPixels
    val profileWidth = activity!!.resources.getDimension(R.dimen.profile_width)
    return Math.floor((widthPx / profileWidth).toDouble()).toInt()

【讨论】:

以上是关于BottomSheetDialogFragment 在横向模式下不显示全高的主要内容,如果未能解决你的问题,请参考以下文章

如果键盘可见,则防止关闭 BottomSheetDialogFragment

赶上BottomSheetDialogFragment的解雇

Android BottomSheetDialogFragment 闪烁

防止 BottomSheetDialogFragment 覆盖导航栏

BottomSheetDialogFragment - 如何包装内容并完全显示?

BottomSheetDialogFragment 不是模态的