4

What I want to do

In a BottomSheetDialogFragment, I want to inflate a view that always stick at the bottom of the screen, no matter what state (collapsed / expanded) the BottomSheetBehavior is in.

What I have done

In a subclass of BottomSheetDialogFragment, I inflate a view from XML and add it as a child of CoordinatorLayout (which is BottomSheetDialogFragment's parent's parent):

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    setupBottomBar(getView());
}

private void setupBottomBar (View rootView) {
    CoordinatorLayout parentView = (CoordinatorLayout) ((FrameLayout)rootView.getParent()).getParent();
    parentView.addView(LayoutInflater.from(getContext()).inflate(R.layout.item_selection_bar, parentView, false), -1);
}

The code runs without error.
And when I use Layout Inspector to look at the View hierarchy, the view structure is also correct:

Layout Inspector Screenshot

You can also download the layout inspector result here, and open it using your own Android Studio.

The problem

However, even though it is inserted as the last child of the CoordinatorLayout, it is still being blocked by the BottomSheetDialogFragment.
When I slowly scroll the BottomSheetDialogFragemnt downwards (from collapsed state to hidden state), I can finally see the view that I want to inflate behind the fragment.

View blocked

Why is this happening?

The answer

As @GoodDev pointed out correctly, it is because the root view (design_bottom_sheet) has been set a Z translation by BottomSheetDialog.
This provides an important information that - not only sequence in a View hierarchy will determine its visibility, but also its Z translation.

The best way is to get the Z value of design_bottom_sheet and set it to the bottom bar layout.

private void setupBottomBar (View rootView) {
    CoordinatorLayout parentView = (CoordinatorLayout) (rootView.getParent().getParent());
    View barView = LayoutInflater.from(getContext()).inflate(R.layout.item_selection_bar, parentView, false);
    ViewCompat.setTranslationZ(barView, ViewCompat.getZ((View)rootView.getParent()));
    parentView.addView(barView, -1);
}
Sira Lam
  • 5,179
  • 3
  • 34
  • 68
  • So what's the root view of your fragment? – CoXier Feb 28 '18 at 09:28
  • It can be obtained by `getView()` inside the `BottomSheetDialogFragment`. If you are asking what is the root element of my fragment's XML, well, it is a `FrameLayout`; but this is not related because this `FrameLayout` refers to the "design_bottom_sheet" in the View hierarchy. – Sira Lam Feb 28 '18 at 09:31

2 Answers2

2

EDIT 2

Ok, now I see your requirement, try this one:

private void setupBottomBar (View rootView) {
    CoordinatorLayout parentView = (CoordinatorLayout) ((FrameLayout)rootView.getParent()).getParent();
    View view = LayoutInflater.from(getContext()).inflate(R.layout.item_selection_bar, parentView, false);
    // using TranslationZ to put the view on top of bottom sheet layout
    view.setTranslationZ(100);
    parentView.addView(view, -1);
}

EDIT:

OK, I check your layout and check the BottomSheetDialogFragment source code, found the reason:

In BottomSheetDialogFragment using BottomSheetDialog dialog, the method setContentView in BottomSheetDialog using wrapInBottomSheet to put the content view in R.id.design_bottom_sheet layout. So you need override the BottomSheetDialogFragment's public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) to fix your problem.

Or, change your setupBottomBar method to:

private void setupBottomBar (View rootView) {
    FrameLayout frame = (FrameLayout)rootView.getParent();
    frame.addView(LayoutInflater.from(getContext()).inflate(R.layout.item_selection_bar, frame, false), -1);
}

and in your item_selection_bar layout file, change height and layout_gravity:

<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_gravity="bottom"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

BottomSheetDialogFragment doc says: Modal bottom sheet. This is a version of DialogFragment that shows a bottom sheet using BottomSheetDialog instead of a floating dialog.

So the BottomSheetDialogFragment is a Dialog, Dialog is a floating view, so will cover the Activity content when BottomSheetDialogFragment is showing.

goodev
  • 624
  • 1
  • 5
  • 10
  • But I am not inserting the view in Activity. I am inserting in the DialoigFragment. – Sira Lam Feb 28 '18 at 09:27
  • Look the `wrapInBottomSheet` method source code, you should add view in `R.id.design_bottom_sheet` FrameLayout. not the Dialog root layout. – goodev Feb 28 '18 at 10:05
  • This is the same as adding the view as part of the XML I inflated in onCreateView, which cannot fulfill the requirement because I need it to stick at the bottom. I guess you may not know - the view you inflated in onCreateView will be partly hidden when the state of BottomSheetBehavior is in `COLLAPSED`. That's why I did such strange thing to inflate it on a higher level in hierarchy. – Sira Lam Feb 28 '18 at 10:09
  • Ok, now I see your requirement, try this one: private void setupBottomBar (View rootView) { CoordinatorLayout parentView = (CoordinatorLayout) ((FrameLayout)rootView.getParent()).getParent(); View view = LayoutInflater.from(getContext()).inflate(R.layout.item_selection_bar, parentView, false); // using TranslationZ to put the view on top of bottom sheet layout view.setTranslationZ(100); parentView.addView(view, -1); } – goodev Feb 28 '18 at 10:33
  • Yes, your EDIT 2 is the correct answer! By the way, for it to work in pre-lollipop device, Use `ViewCompat.setTranslationZ(view, 100)` instead. And as @CoXier suggested, get the translaztionZ value from the bottomSheet is better than using `100`. Thanks! – Sira Lam Mar 01 '18 at 02:24
  • I use `getZ()` instead of `getTranslaztionZ ()`. – CoXier Mar 01 '18 at 06:17
1

@goodev has give a nice answer.

Your problem

View's Z position causes this problem. Although the TextView is the last position you still can not see it.

enter image description here enter image description here

How to solve

You can set design_sheet_bottom's Z to TextView.

 private void setupBottomBar (View rootView) {
    CoordinatorLayout parentView = (CoordinatorLayout) ((FrameLayout)rootView.getParent()).getParent();
    View view = LayoutInflater.from(getContext()).inflate(R.layout.item_selection_bar, parentView, false);
    view.setZ(((View)rootView.getParent()).getZ());
    parentView.addView(view, -1);
}

And I think above way is very boring, can you put your two view RecyclerView and TextView into a layout ? Then you can inflate theme together in onCreateView() method.

CoXier
  • 2,523
  • 8
  • 33
  • 60
  • You have got it right. However, you still don't understand why putting those 2 views in a layout won't work lol. The `RecyclerView`, which is inside the `design_bottom_sheet`, can be collapsed or expanded by user. This is a fundamental feature of `BottomSheetDialog`. And unless the state of `BottomSheetBehavior` is in `EXPANDED`, the bottom part of the sheet will be hidden below the screen. That's why I cannot put the `TextView` in the same layout with `RecyclerView` because it will be hidden, but I need it to stick at the bottom. – Sira Lam Mar 01 '18 at 02:27
  • Btw, +1 for getting Z value from rootView! – Sira Lam Mar 01 '18 at 02:27