【问题标题】:BottomSheetDialog get Behavour always returns nullBottomSheetDialog get Behavour 总是返回 null
【发布时间】:2018-11-18 12:01:57
【问题描述】:

我使用 BottomSheetDialog 并且我必须获得 Behavior 以便可以设置 setBottomSheetCallback() 来处理一些事情。

作为google says,我必须将 Coordinator 放在 parentView 上并为其添加行为。我在 MainActivity(根活动)中定义了 CoordinatorLayout,如下所示:

<android.support.design.widget.CoordinatorLayout
    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:tag="coordinatorLayout"
    app:layout_behavior="android.support.design.widget.BottomSheetBehavior"

...

这是尝试从活动中获取:

 public void setupDialog(final Dialog dialog, int style) {

 CoordinatorLayout coordinatorLayout = getActivity().getWindow().getDecorView();
 BottomSheetBehavior behavior = BottomSheetBehavior.from(coordinatorLayout);

我也试过了:

CoordinatorLayout coordinatorLayout = getActivity().getWindow().getDecorView().findViewById(R.id.coordinatorLayout); 
//this is point to the coordinatorView 

BottomSheetBehavior behavior = BottomSheetBehavior.from(coordinatorLayout);
//But this returns same error that "The view is not a child of CoordinatorLayout"

如您所见,我通过了协调器布局,但方法无法在其中找到行为。 我还应该提到使用 BottonSheetDialog 的要点:

  1. 我这样展示我的 BottonSheetFragments:
  2. 我在 OnCreateView 中(不是在 setupDialog() 中)增加了我的 BottomSheetDialog,以便在其中添加 View Pager。您可能知道,如果您在 onSetupDialog() 中膨胀视图,ViewPager 不会附加到 BottonSheetDialog。

我无法获得父级 CoordinatorLayout 的行为。 在我的 bottonSheetDialog 中,我尝试了这些方法,但它们都不起作用,我得到 "The view is not a child of CoordinatorLayout" 错误。

第 1 点的代码:

MyFragment myFragment= MyFragment.getInstance(bundle);
myFragment.show(fragment.getChildFragmentManager(),"tag");

第 2 点的代码:

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

【问题讨论】:

  • BottomSheetDialog 有点奇怪。它实际上并未添加到您的CoordinatorLayout。它以透明背景全屏显示,并在内部设置了自己的CoordinatorLayout,并将底部工作表添加到其中。它还在上面设置了自己的私有BottomSheetCallback,你不能真正干涉它。你可以用BottomSheetBehavior 设置你自己的View 吗?
  • 实际上,现在我再次查看源代码,回调所做的唯一事情是cancel() Dialog in onStateChanged() if newState == BottomSheetBehavior.STATE_HIDDEN,你可以在你的自己的回调。如果你想试试这个,在BottomSheetDialog 上调用findViewById(R.id.design_bottom_sheet) 会给你内部FrameLayoutBottomSheetBehavior
  • @MikeM。让我检查一下。
  • 不,特别是R.id.design_bottom_sheet。它是BottomSheetDialog 中内部底部工作表FrameLayout 的ID。它在设计库中定义。您无需定义该 ID。
  • 谢谢。很用满。我想现在你可以发布答案了。

标签: android android-coordinatorlayout behavior


【解决方案1】:

BottomSheetDialog 是一个相当奇特的Dialog 实现。它不会添加到您的Activity 布局中的CoordinatorLayout*。它在内部设置了自己的CoordinatorLayout,并在其中设置了带有BottomSheetBehaviorFrameLayout,您的View 将放置在其中。 BottomSheetDialog 本身填满了整个屏幕,并且有一个透明的背景,这样它就可以处理底部的表单交互,以及任何外部触摸。

如果您需要访问该底部工作表及其BottomSheetBehavior,我们需要从DialogView 层次结构中获取它。这就像在Dialog 上调用findViewById(R.id.design_bottom_sheet) 一样简单,但是我们需要等到Dialog 显示出来才能修改BottomSheetBehavior。此外,由于BottomSheetDialog 设置了自己的BottomSheetCallback,因此我们必须确保适当地替换它。也就是说,我们必须注意在Dialog 达到关闭状态时取消它。例如:

final BottomSheetDialog bsd = new BottomSheetDialog(MainActivity.this);
bsd.setContentView(R.layout.your_dialog_layout);
bsd.show();

FrameLayout bottomSheet = (FrameLayout) bsd.findViewById(R.id.design_bottom_sheet);
BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
        @Override
        public void onStateChanged(View bottomSheet, int newState) {
            // This is the crucial bit.
            if (newState == BottomSheetBehavior.STATE_HIDDEN) {
                bsd.cancel();
            }
        }

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

如果您使用的是BottomSheetDialogFragmentDialog 会显示在DialogFragmentonStart() 中,我们可以在super 调用之后重写该方法以在那里进行修改。例如:

public class MyFragment extends BottomSheetDialogFragment {
    public MyFragment() {}

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.your_dialog_layout, container, false);
    }

    @Override
    public void onStart() {
        super.onStart();

        FrameLayout bottomSheet = getDialog().findViewById(R.id.design_bottom_sheet);
        BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
        behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
                @Override
                public void onStateChanged(View bottomSheet, int newState) {
                    // This is the crucial bit.
                    if (newState == BottomSheetBehavior.STATE_HIDDEN) {
                        getDialog().cancel();
                    }
                }

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

在任何一种情况下,您都可以在BottomSheetCallback 中做几乎任何您想做的事情,只要您在onStateChanged()cancel() DialognewState == BottomSheetBehavior.STATE_HIDDEN


*顺便说一句,这意味着您不必在 Activity'a 布局中使用 CoordinatorLayout 即可使用 BottomSheetDialogBottomSheetDialogFragment,尽管我不确定这是否在任何地方都明确在文档或其他开发者资源中。

【讨论】:

  • 完整实用。
【解决方案2】:

在您的 CoordinatorLayout 中,您的孩子有这个 app:layout_behavior="android.support.design.widget.BottomSheetBehavior"

所以你需要BottomSheetBehavior behavior = BottomSheetBehavior.from(your CoordinatorLayout child);

你需要在上面设置 setBottomSheetCallback。 behavior.setBottomSheetCallback(...)

【讨论】:

  • 我的主要活动 rootView 是具有该行为的 CoordinatorLayout 的子项。
  • 主Activity的根布局是什么?
  • 正如我所描述的,它是 CoordinatorLayout。
  • 如果我正确理解 CoordinatorLayout 里面的 CoordinatorLayout?
  • 这很奇怪。当我在 setupDialog() 上添加 getDialog().findViewById(R.id.design_bottom_sheet) 并返回 null 但是当我按照你提到的那样调用它时,它起作用了。是回答。谢谢。
猜你喜欢
  • 2016-07-10
  • 2014-03-04
  • 2016-11-02
  • 2014-05-06
  • 2012-06-05
  • 2014-05-30
  • 2014-02-23
  • 2017-10-12
  • 2013-08-16
相关资源
最近更新 更多