底部弹出窗口在横屏时的问题

30

在横屏模式下显示底部对话框时,我遇到了错误的行为。该问题发生在 design library 的 24.+ 版本中。根据下面的图片,在横屏模式下 Bottom Sheet 没有正确地显示。我正在使用 BottomSheetDialog 类,并且我正在遵循这个教程:http://www.skholingua.com/blog/bottom-sheet-android,在我的发布应用程序中也出现了问题。

我测试了 25.+ 版本,但问题并未得到解决。

在 landscape 24、25.+ Library 中的错误

Error In landscape

在 23.+ Library 中相同的示例

same example in 23.+ Library

主要活动

public class MainActivity extends AppCompatActivity {
CoordinatorLayout coordinatorLayout;
private BottomSheetBehavior<View> mBottomSheetBehavior;
private TextView textView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    coordinatorLayout = (CoordinatorLayout) findViewById(R.id.main_content);
    textView = (TextView) findViewById(R.id.textView);
    View bottomSheet = coordinatorLayout.findViewById(R.id.bottom_sheet);

    //For your bottom sheet to be displayable, you need to create a BottomSheetBehavior.
    //This is created by getting a reference to the container view and calling BottomSheetBehavior.from() on that container.
    mBottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);

    mBottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
        @Override
        public void onStateChanged(@NonNull View bottomSheet, int newState) {
            switch (newState) {
                case BottomSheetBehavior.STATE_DRAGGING:
                    break;
                case BottomSheetBehavior.STATE_COLLAPSED:
                    mBottomSheetBehavior.setPeekHeight(0);
                    break;
                case BottomSheetBehavior.STATE_EXPANDED:
                    break;
                case BottomSheetBehavior.STATE_HIDDEN:
                    break;
                case BottomSheetBehavior.STATE_SETTLING:
                    break;
            }
        }

        @Override
        public void onSlide(@NonNull View bottomSheet, float slideOffset) {
        }
    });

}


public void onClick(View v) {
    switch (v.getId()) {
        case R.id.button1:
            /**
             * For persistent bottom sheet to work, your layout should contain a coordinator layout,
             * and then in any child view of your coordinator layout, you can make it as a persistent bottom sheet
             * by adding a custom property app:layout_behavior and use behavior_peekHeight to define how much
             * of the Bottom Sheet you want visible.
             */
            textView.setText(R.string.dynamic_persistent_txt);
            mBottomSheetBehavior.setPeekHeight(300);
            mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
            break;
        case R.id.button2:
            /**
             * You can also display a Dialog in place of a View in the bottom sheet.
             * To do this, get the view from getLayoutInflater and pass it setContentView of the Dialog.
             */
            View view = getLayoutInflater().inflate(R.layout.bottom_sheet_layout, null);
            TextView textView = (TextView) view.findViewById(R.id.textView);
            textView.setText(R.string.dialog_modal_txt);
            BottomSheetDialog dialog = new BottomSheetDialog(this);
            dialog.setContentView(view);
            dialog.show();
            break;
        case R.id.button3:
            /**
             * You can also display a Fragment in place of a View in the bottom sheet.
             * To do this, you class that extends BottomSheetDialogFragment.
             */
            BottomSheetDialogFragment bottomSheetDialogFragment = new BottomSheetDialogFragmentExample();
            bottomSheetDialogFragment.show(getSupportFragmentManager(), bottomSheetDialogFragment.getTag());
            break;
    }
}

activity_main.xml

<android.support.design.widget.CoordinatorLayout     xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingTop="24dp"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="Dynamic BottomSheet" />

    <Button
        android:id="@+id/button2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="BottomSheetDialog" />

    <Button
        android:id="@+id/button3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="BottomSheetDialogFragment" />
</LinearLayout>

<LinearLayout
    android:id="@+id/bottom_sheet"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:elevation="4dp"
    android:minHeight="120dp"
    android:orientation="vertical"
    android:padding="@dimen/activity_vertical_margin"
    app:behavior_peekHeight="120dp"
    app:layout_behavior="android.support.design.widget.BottomSheetBehavior">

    <include layout="@layout/bottom_sheet_layout" />

</LinearLayout>

</android.support.design.widget.CoordinatorLayout>

底部弹出框布局文件

<?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="match_parent"
android:background="@color/CreamyGreen"
android:orientation="vertical">


<TextView
    android:id="@+id/textView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/static_persistent_txt"
    android:padding="16dp"
    android:textAppearance="?android:attr/textAppearanceMedium"
    android:textColor="@android:color/white" />

<TextView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    android:text="@string/ipsum"
    android:textColor="@android:color/white"
    android:textSize="16sp" />
</LinearLayout>

1
尽管我同意它看起来不对劲,感觉很愚蠢,但我认为这是有意为之的。AUTO高度设置强制底部面板不会超出16:9比例关键线...在横向模式下看起来很愚蠢... - Zordid
9
我在Android问题跟踪器上提交了一个问题,并收到了解决该问题的可能方法,请参见:https://code.google.com/p/android/issues/detail?id=231964#c6。 - Fernando Andrauss
10个回答

28

这可以用两行代码实现(Kotlin版本)

class MyBottomSheetFragment : BottomSheetDialogFragment() {
    //....
    override fun onStart() {
        super.onStart()
        //this forces the sheet to appear at max height even on landscape
        val behavior = BottomSheetBehavior.from(requireView().parent as View)
        behavior.state = BottomSheetBehavior.STATE_EXPANDED
    }
}

1
运行得很好。谢谢。 - Izak
谢谢!这个帮我省下了一大堆工作! - Silverbaq

17

谷歌人员将此视为预期工作,以下是解决方法

屏幕高度比例有一个神奇的常数,它似乎执行 min(actualwidth, themewidth), 但显然在手机横屏模式下无法很好地运行,因此要将其覆盖为更大的值。

<style name="Theme.Main.Reader">
     ...
     <item name="bottomSheetDialogTheme">@style/ReaderBottomSheelDialog</item>
</style>
<style name="ReaderBottomSheelDialog" parent="Theme.Design.BottomSheetDialog">
     <item name="bottomSheetStyle">@style/BottomSheetStyle</item>
</style>

<style name="BottomSheetStyle" parent="Widget.Design.BottomSheet.Modal">
    <item name="behavior_peekHeight">512dp</item>
</style>

谢谢,这个很好用。我只需要使用Theme.Design.Light.BottomSheetDialog来匹配我的应用程序主题即可。 - k2col
这个解决方案有一个副作用 - 屏幕旋转后ActionBar中的字幕会消失。 - isabsent

12

这是一个解决方法。(注意:此代码在活动中)

View sheetView;//class level variable

private void setUpBottomSheetDialog() {

    bottomSheetDialog = new BottomSheetDialog(this);

    LayoutInflater inflater = LayoutInflater.from(this);
     sheetView = inflater.inflate(R.layout.bottom_sheet_image_source, (ViewGroup) this.getWindow().getDecorView().getRootView(), false);

    bottomSheetDialog.setContentView(sheetView);

    BottomSheetBehavior mBehavior = BottomSheetBehavior.from((View) sheetView.getParent());

    bottomSheetDialog.setOnShowListener(dialogInterface -> {
        mBehavior.setPeekHeight(sheetView.getHeight());//get the height dynamically
    });
}

10

个人解决此问题的选择是,在onCreateView之后,您已经拥有了BottomSheetDialogFragment的主视图。

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    mainLayout = inflater.inflate(R.layout.fragment_auction_bottom_sheet_dialog, container, false);
    return mainLayout;
}

当你创建了View后,onStart将会被执行,因此你可以与这个行为进行玩耍

@Override
public void onStart() {
    super.onStart();
    //this expands the bottom sheet even after a config change
    bottomSheetBehavior = BottomSheetBehavior.from((View) mainLayout.getParent());
    bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}

那么您将始终保持底部工作表展开


这个可以运作,但它也会在所有情况下都全屏显示。我该如何让它以不同的方式工作呢?例如,我注意到共享底部表格在横向和纵向时是不同的。在纵向时它只占屏幕的一部分,在横向时占据整个屏幕。我不知道它的逻辑是什么。可能不仅仅是检查横屏因为它在分屏模式下也是占据整个空间。 - android developer

5
为了让BottomSheetDialogFragment始终完全展开(包括横向模式),我执行以下操作。
在onCreateDialog中,您创建BottomSheetDialog和视图。将此视图添加到BottomSheetDialog后,您可以使用BottomSheetBehavior.from()中的视图父级来获取BottomSheetBehavior。
然后,在BottomSheetDialogFragment的onStart中,您调用 BottomSheetBehavior.setState并使用STATE_EXPANDED参数。
BottomSheetBehavior mBottomBehavior;

public Dialog onCreateDialog(Bundle savedInstanceState) {
    BottomSheetDialog dialog = new BottomSheetDialog(getContext());
    mBinding = SomeBinding.inflate(LayoutInflater.from(getContext()));
    dialog.setContentView(mBinding.getRoot());
    mBottomBehavior = BottomSheetBehavior.from((View) mBinding.getRoot().getParent());
    return dialog;
}

public void onStart() {
    super.onStart();
    mBottomBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}

希望这能对某些人有所帮助。


这个可以工作,但是BottomSheet还有另一个bug - 在STATE_EXPANDED状态下会移除圆角。经典的Google员工 - 他们就是什么都做不好,他们的每个组件都有多个重大的bug。啊,Google! - qkx

2

BottomSheetDialog 对话框; BottomSheetBehavior 底部弹出窗口行为;

private void createBottomSheet() {
    if (dialog == null){
        dialog = new BottomSheetDialog(this);

        final View view = LayoutInflater.from(this).inflate(R.layout.setting_dialog,
                (ViewGroup)this.getWindow().getDecorView().getRootView(),false);

        dialog.setContentView(view);
        bottomSheetBehavior = BottomSheetBehavior.from((View)view.getParent());
        dialog.setOnShowListener(new DialogInterface.OnShowListener() {
            @Override
            public void onShow(DialogInterface dialog) {
                bottomSheetBehavior.setPeekHeight(view.getHeight());
            }
        });
    }
}

2
在AndroidX中,底部工作表可以按如下方式展开:
 BottomSheetDialog bottomSheetDialog = 
       new BottomSheetDialog(requireContext());

  bottomSheetDialog.setContentView(view);

    bottomSheetDialog.show();

    FrameLayout bottomSheet = (FrameLayout)
            bottomSheetDialog.findViewById(com.google.android.material.R.id.design_bottom_sheeet);
    BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
    behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
    behavior.setPeekHeight(0);

这也有助于解决获取底部表单行为时出现以下错误的情况: “视图不是CoordinatorLayout的子级”。

0
将此函数添加到扩展BottomSheetDialogFragment类的实现中即可完成所需操作:
@Override
public void onStart() {
    super.onStart();
    BottomSheetBehavior.from((View) requireView().getParent()).setState(BottomSheetBehavior.STATE_EXPANDED);
    //  Opens the bottom sheet in expanded state even in landscape mode
    BottomSheetBehavior.from((View) requireView().getParent()).setSkipCollapsed(true);
    //  Skips the peek view of the bottom sheet
}

0

没有必要使用各种变通方法。您只需设置所需的高度即可。您可以选择任何逻辑,包括当前屏幕高度的百分比。以下是将其设置为屏幕高度的一半的示例:

val bottomSheetDialog = BottomSheetDialog(this)
val dialogBinding = BottomSheetDialogBinding.inflate(layoutInflater)
bottomSheetDialog.setContentView(dialogBinding.root)
val screenHeight = resources.displayMetrics.heightPixels 
bottomSheetDialog.behavior.peekHeight = screenHeight / 2
bottomSheetDialog.show()

0

在我的情况下,我已经以编程方式创建了底部表的视图。 这是我展示底部表的代码:

private void showButtonSheet() {
        BottomSheetCustomView contentView = new BottomSheetCustomView(getContext());
        BottomSheetDialog bottomSheet = new BottomSheetDialog(getContext(), R.style.BottomSheetDialog);
        bottomSheet.setContentView(contentView);
        BottomSheetBehavior behavior = new BottomSheetBehavior().from((View) contentView.getParent());
        behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
        bottomSheet.setOnShowListener(dialogInterface -> {
            behavior.setPeekHeight(contentView.getHeight());//get the height dynamically
            behavior.setMaxWidth(contentView.getWidth());
        });
        showDialog(bottomSheet);
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接