Persistent BottomSheet Below Fragment Contents?

2019-05-10 02:06发布

问题:

Using a Persistent BottomSheet, within a CoordinatorLayout, how can one prevent the BottomSheet from covering other user interface elements when the BottomSheet is in its COLLAPSED aka peeked state?

I've successfully added a BottomSheet to my Navigation Drawer & Fragment based application; however, as mentioned above, the BottomSheet covers user interface elements within my fragment container when it's either COLLAPSED or EXPANDED

Covering part of the fragment is ok when the BottomSheet is expanded since, if needed, users can collapse the BottomSheet to its peek state. However, I've explicitly disabled* the user from hiding the BottomSheet and thus need a way of ensuring the fragment container remains above the BottomSheet at all times when the BottomSheet is in its collapsed state. Photos are worth a thousand words so hopefully the following clarify the issue


Above: A redacted screenshot of a fragment with two buttons, A & B, near the bottom of the screen. Note: The fragment's root is a scrollview which is why button B is cut off by the System's Back and Home buttons


Above: The same fragment as seen above but with the BottomSheet fully expanded. For reference the BottomSheet is everything below and including the green bar. Note: The fact that the BottomSheet covers button A & B is ok since the BottomSheet is fully expanded


Above: The same fragment as seen above but with the BottomSheet in its collapsed state. Note: Now that the BottomSheet is fully collapsed and cannot be collapsed further the issue can be seen in that it covers part of button B and more importantly the fragment scrolls below the BottomSheet


Originally I was hoping to fix the issue by subclassing AppBarLayout.ScrollingViewBehavior similar to this answer. Sadly I was unable adjust the child view's height within CoordinatorLayout.Behavior#onDependentViewChanged. When called, the child's height appears unset (-1) and adding a OnLayoutChangedListener requires the child to be final making it impossible to update the height once the height is defined in the layout changed listener callback. I'd still like to solve the problem using a subclassed Behavior but for the time being I'm stumped

My next thought was to add a "spacer" view to each of my fragment layouts using the <include/> tag. I then could provide add/show and remove/hide helper methods to an abstract base fragment class which all fragments needing to display the BottomSheet would extend. This spacer view would be programmatically assigned the peek height of the BottomSheet making room for it within the fragment. The BottomSheet would then cover the spacer view which is fine since I don't consider it part of the fragment's usable view area. I'm currently working on implementing this approach and while I think it'll work I'm skeptical it's good solution

Any advice, suggestions, and potential solutions are welcome and thanks in advance!

And to clarify below is a condensed version of my top-level application layout

<android.support.v4.widget.DrawerLayout>

    <android.support.design.widget.CoordinatorLayout>

        <android.support.design.widget.AppBarLayout>

            <android.support.design.widget.CollapsingToolbarLayout>

                <ImageView ... />

                <android.support.v7.widget.Toolbar ... />
            </android.support.design.widget.CollapsingToolbarLayout>
        </android.support.design.widget.AppBarLayout>

        <!-- All fragments assume the following view container via a FragmentTransaction's  
             replace method which in pseudocode looks something like
             FragmentTransaction.replace(R.id.main_activity_fragment_container,
             fragment, ...).commit();
        -->
        <FrameLayout android:id="@+id/main_activity_fragment_container" ... />

        <com.xyz.abc.view.BottomSheetView ... />

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

    <android.support.design.widget.NavigationView ... />
</android.support.v4.widget.DrawerLayout>

*It appears BottomSheetBehavior#mHideable} is false by default