Search code examples
androidviewandroid-coordinatorlayoutbottom-sheetview-hierarchy

View is in the last position of parent, but still being blocked


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);
}

Solution

  • 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.