Java Android BottomSheetDialogFragment 没有完全展开

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37555403/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 19:27:19  来源:igfitidea点击:

Android BottomSheetDialogFragment does not expand completely

javaandroidandroid-support-libraryandroid-support-designbottom-sheet

提问by Nandish A

I have the following test bottom sheet implementation.

我有以下测试底部工作表实现。

When I set the peekHeight to a value less than 500, it works. After some value, any increase in peek height will not change how the bottom sheet is expanded. It Just remains there to only drag manually. How do we set the peekHeight programmatically to ensure that the bottom sheet is auto expanded to the peek height.

当我将 peekHeight 设置为小于 500 的值时,它会起作用。在某个值之后,任何窥视高度的增加都不会改变底部工作表的展开方式。它只是留在那里只能手动拖动。我们如何以编程方式设置 peekHeight 以确保底部工作表自动扩展到 peek 高度。

enter image description here

在此处输入图片说明

bottom_sheet_dialog_main

bottom_sheet_dialog_main

<?xml version="1.0" encoding="utf-8"?>
<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/locUXCoordinatorLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:id="@+id/locUXView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true"
        android:orientation="vertical"
        app:behavior_hideable="false"
        app:behavior_peekHeight="0dp"
        app:layout_behavior="@string/bottom_sheet_behavior">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="1 Value" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="2 Value" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="3 Value" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="4 Value" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="5 Value" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="6 Value" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="7 Value" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="8 Value" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="9 Value" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="First Value" />
    </LinearLayout>
</android.support.design.widget.CoordinatorLayout>

Java code

Java代码

public class MyBottomSheetDialogFragment extends BottomSheetDialogFragment {

    private static BottomSheetBehavior bottomSheetBehavior;
    private static View bottomSheetInternal;
    private static MyBottomSheetDialogFragment INSTANCE;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        getDialog().setOnShowListener(new DialogInterface.OnShowListener() {
            @Override
            public void onShow(DialogInterface dialog) {
                BottomSheetDialog d = (BottomSheetDialog) dialog;
                CoordinatorLayout coordinatorLayout = (CoordinatorLayout)d.findViewById(R.id.locUXCoordinatorLayout);
                bottomSheetInternal = d.findViewById(R.id.locUXView);
                bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetInternal);
                bottomSheetBehavior.setPeekHeight(bottomSheetInternal.getHeight());
                bottomSheetInternal.requestLayout();
                coordinatorLayout.getLayoutParams().height = bottomSheetInternal.getHeight();
                Toast.makeText(getActivity(), "Height is" + bottomSheetInternal.getHeight() + "  " + coordinatorLayout.getLayoutParams().height, Toast.LENGTH_LONG).show();

            }
        });
        INSTANCE = this;
        return inflater.inflate(R.layout.bottom_sheet_dialog_main, container, false);
    }
}

采纳答案by Nandish A

By deeper UI inspection, we find that there is another CoordinatorLayoutthat wraps our coordinator layout. The parent CoordinatorLayouthas a FrameLayoutwith a BottomSheetBehaviorwith the id design_bottom_sheet. The peek height set from our code above was getting constrained due the match_parentheight of the FrameLayoutwith the id design_bottom_sheet

通过更深入的 UI 检查,我们发现还有一个CoordinatorLayout包装我们的协调器布局。家长CoordinatorLayoutFrameLayout一个BottomSheetBehaviorid为design_bottom_sheet。由于带有 id的match_parent高度,从我们上面的代码中设置的窥视高度受到限制FrameLayoutdesign_bottom_sheet

By setting the peek height of the FrameLayoutwith the id design_bottom_sheet , this issue was resolved

通过设置FrameLayout带有 id design_bottom_sheet的 peek height ,这个问题得到解决

    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    getDialog().setOnShowListener(new DialogInterface.OnShowListener() {
        @Override
        public void onShow(DialogInterface dialog) {
            BottomSheetDialog d = (BottomSheetDialog) dialog;
            coordinatorLayout = (CoordinatorLayout) d.findViewById(R.id.locUXCoordinatorLayout);
            bottomSheetInternal = d.findViewById(R.id.locUXView);
            bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetInternal);
            bottomSheetBehavior.setHidable(false);
            BottomSheetBehavior.from((View)coordinatorLayout.getParent()).setPeekHeight(bottomSheetInternal.getHeight());
            bottomSheetBehavior.setPeekHeight(bottomSheetInternal.getHeight());
            coordinatorLayout.getParent().requestLayout();

        }
    });

回答by Denshov

I've found another solution. Maybe for future readers it can be useful.

我找到了另一个解决方案。也许对未来的读者来说它可能很有用。

@Override
public void setupDialog(Dialog dialog, int style) {
    super.setupDialog(dialog, style);
    final View root = View.inflate(getContext(), R.layout.fragment_bottom_sheet_choose_time, null);
    dialog.setContentView(root);
    initView(root);

    CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) ((View) root.getParent()).getLayoutParams();
    CoordinatorLayout.Behavior behavior = params.getBehavior();

    if (behavior != null && behavior instanceof BottomSheetBehavior) {
        mBottomSheetBehavior = (BottomSheetBehavior) behavior;
        mBottomSheetBehavior.setBottomSheetCallback(mBottomSheetBehaviorCallback);

        root.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                root.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                int height = root.getMeasuredHeight();
                mBottomSheetBehavior.setPeekHeight(height);
            }
        });
    }
}

As @Anthonyeef mentioned, here ViewTreeObserveris aimed to get the exact measure height after the view is really measured and the GlobalOnLayoutListeneris removed for better performance.

正如@Anthonyeef 所提到的,这里ViewTreeObserver的目的是在真正测量视图后获得准确的测量高度,并GlobalOnLayoutListener删除该高度以获得更好的性能。

But please, before using in production, test this solution on different devices and screens, because if your content in bottom sheet is higher than your screen it can produce some strange swipe behavior.

但是,在生产中使用之前,请在不同的设备和屏幕上测试此解决方案,因为如果底部工作表中的内容高于屏幕,它可能会产生一些奇怪的滑动行为。

回答by athysirus

Using this code in onCreateView.

在 onCreateView 中使用此代码。

getDialog().setOnShowListener(new DialogInterface.OnShowListener() {
        @Override
        public void onShow(DialogInterface dialog) {
            BottomSheetDialog d = (BottomSheetDialog) dialog;
            FrameLayout bottomSheet = (FrameLayout) d.findViewById(R.id.design_bottom_sheet);
            CoordinatorLayout coordinatorLayout = (CoordinatorLayout) bottomSheet.getParent();
            BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
            bottomSheetBehavior.setPeekHeight(bottomSheet.getHeight());
            coordinatorLayout.getParent().requestLayout();
        }
    });

回答by Mike T

Thanks @athysirus for the neat approach. Here is the version I ended up with, in case somebody wants to have a working kotlin sample.

感谢@athysirus 的简洁方法。这是我最终得到的版本,以防有人想要一个可用的 kotlin 样本。

Important to note is, that you should also remove the global layout listener, once done.

需要注意的是,一旦完成,您还应该删除全局布局侦听器。

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    view.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
        override fun onGlobalLayout() {
            val bottomSheet = (dialog as BottomSheetDialog).findViewById<View>(com.google.android.material.R.id.design_bottom_sheet)
            BottomSheetBehavior.from<View>(bottomSheet).apply {
                state = BottomSheetBehavior.STATE_EXPANDED
                peekHeight = 0
            }
            view.viewTreeObserver.removeOnGlobalLayoutListener(this)
        }
    })

回答by Paul Spiesberger

Solution in Kotlin inspired by Nandish A's post in more detail. First the layout:

Kotlin 中的解决方案更详细地受Nandish A的帖子启发。首先布局:

<androidx.coordinatorlayout.widget.CoordinatorLayout
        android:id="@+id/container_root"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/bottom_sheet"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:behavior_hideable="false"
            app:behavior_peekHeight="0dp"
            app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">

                  <!-- content of the bottom sheet -->

        </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

And then put this into your BottomSheetDialogFragment:

然后把它放到你的BottomSheetDialogFragment

override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        // ...        

        dialog.setOnShowListener {

            val root = dialog.find<CoordinatorLayout>(R.id.container_root)
            val bottomSheetInternal = root.find<ConstraintLayout>(R.id.bottom_sheet)

            val bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetInternal)
            bottomSheetBehavior.isHideable = false
            BottomSheetBehavior.from(root.parent as View).peekHeight = root.height
            bottomSheetBehavior.peekHeight = root.height
            root.parent.requestLayout()
        }

        // ...
    }

回答by Saba 21

this is how I set peek_heightand layout_heightto bottom sheet view in BottomSheetDialogFragment

这就是我设置peek_heightlayout_height底部工作表视图的方式BottomSheetDialogFragment

dialog?.setOnShowListener {
                val dialog = dialog as BottomSheetDialog
                val bottomSheet = dialog.findViewById<FrameLayout>(R.id.design_bottom_sheet)
                val coordinatorLayout = bottomSheet?.parent as? CoordinatorLayout
                val bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet)
                bottomSheet?.viewTreeObserver?.addOnGlobalLayoutListener {
                    bottomSheet.viewTreeObserver.removeOnGlobalLayoutListener {}
                    bottomSheetBehavior.peekHeight = getPopupHeight(.5f)
                    val params = bottomSheet.layoutParams
                    params.height = getPopupHeight(1f)
                    bottomSheet.layoutParams = params
                    coordinatorLayout?.parent?.requestLayout()
                }
            }

this method to get percent of screen height

此方法获取屏幕高度的百分比

 private fun getPopupHeight(percent: Float): Int {
        val displayMetrics = DisplayMetrics()
        activity?.windowManager?.defaultDisplay?.getMetrics(displayMetrics)
        return (displayMetrics.heightPixels * percent).toInt()
    }

回答by Muhammad Umair Shafique

Kotlinsafe way of achieving this is:

Kotlin实现这一目标的安全方法是:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    dialog.setOnShowListener {
        val dialog = it as BottomSheetDialog
        val bottomSheet = dialog.findViewById<View>(R.id.design_bottom_sheet)
        bottomSheet?.let { sheet ->
            dialog.behavior.peekHeight = sheet.height
            sheet.parent.parent.requestLayout()
        }
    }
}

NOTE:No need to wrap your layout in coordinator layout.

注意:无需将您的布局包装在协调器布局中。

Works like charm.

像魅力一样工作。

回答by seinta

This made the trick for me! My class extends the BottomSheetDialogFragment

这对我来说是个窍门!我的课程扩展了BottomSheetDialogFragment

@Override
public void onStart()
{
    super.onStart();
    Dialog dialog = getDialog();

    if (dialog != null)
    {
        View bottomSheet = dialog.findViewById(R.id.bottom_sheet);
        bottomSheet.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
    }
    View view = getView();
    view.post(() -> {
        View bottomSheet = dialog.findViewById(R.id.bottom_sheet);
        View parent = (View) view.getParent();
        CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) (parent).getLayoutParams();
        CoordinatorLayout.Behavior behavior = params.getBehavior();
        BottomSheetBehavior bottomSheetBehavior = (BottomSheetBehavior) behavior;
        bottomSheetBehavior.setPeekHeight(view.getMeasuredHeight());
        ((View) bottomSheet.getParent()).setBackgroundColor(Color.TRANSPARENT);
    });
}

@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    View view = inflater.inflate(R.layout.screen_delivery_type, container, false);

    getDialog().setOnShowListener(new DialogInterface.OnShowListener()
    {
        @Override
        public void onShow(DialogInterface dialog)
        {
            BottomSheetDialog d = (BottomSheetDialog) dialog;
            FrameLayout bottomSheet = (FrameLayout) d.findViewById(R.id.bottom_sheet);
            CoordinatorLayout coordinatorLayout = (CoordinatorLayout) bottomSheet.getParent();
            BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
            bottomSheetBehavior.setPeekHeight(bottomSheet.getHeight());
            bottomSheetBehavior.setFitToContents(true);
            bottomSheetBehavior.setExpandedOffset(0);
            bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
            coordinatorLayout.getParent().requestLayout();
        }
    });
}