How to mimic Google Maps' bottom-sheet 3 phases behavior?

后端 未结 4 584
青春惊慌失措
青春惊慌失措 2020-12-04 05:11

Background

I\'m assigned to make a UI that behaves similar to how Google Maps shows a bottom-sheet for a found result.

It has three different phases:

4条回答
  •  广开言路
    2020-12-04 05:23

    Note: Read the edits at the bottom


    OK, I've found a way to do it, but I had to change the code of multiple classes, so that the bottom sheet would know of the state of the appBarLayout (expanded or not), and ignore scroll-up in case it's not expanded:

    BottomSheetLayout.java

    Added fields:

    private AppBarLayout mAppBarLayout;
    private OnOffsetChangedListener mOnOffsetChangedListener;
    private int mAppBarLayoutOffset;
    

    init() - added this:

        mOnOffsetChangedListener = new OnOffsetChangedListener() {
            @Override
            public void onOffsetChanged(final AppBarLayout appBarLayout, final int verticalOffset) {
                mAppBarLayoutOffset = verticalOffset;
            }
        };
    

    Added function to set the appBarLayout:

    public void setAppBarLayout(final AppBarLayout appBarLayout) {
        if (mAppBarLayout == appBarLayout)
            return;
        if (mAppBarLayout != null)
            mAppBarLayout.removeOnOffsetChangedListener(mOnOffsetChangedListener);
        mAppBarLayout = appBarLayout;
        mAppBarLayout.addOnOffsetChangedListener(mOnOffsetChangedListener);
    }
    

    onDetachedFromWindow() - added this:

        if (mAppBarLayout != null)
            mAppBarLayout.removeOnOffsetChangedListener(mOnOffsetChangedListener);
    

    onTouchEvent() - added this:

          ...
          if (bottomSheetOwnsTouch) {
            if (state == State.EXPANDED && scrollingDown && mAppBarLayout != null && mAppBarLayoutOffset != 0) {
                event.offsetLocation(0, sheetTranslation - getHeight());
                getSheetView().dispatchTouchEvent(event);
                return true;
            }
          ...
    

    Those were the main changes. Now for what sets them:

    MyFragment.java

    onCreateView() - added this:

        mBottomSheetLayout.setAppBarLayout((AppBarLayout) view.findViewById(R.id.appbar));
    

    I also added this function:

     public void setBottomSheetLayout(final BottomSheetLayout bottomSheetLayout) {
        mBottomSheetLayout = bottomSheetLayout;
    }
    

    Now this is how the activity tells the fragment about the appBarLayout:

                final MyFragment myFragment = new MyFragment();
                myFragment.setBottomSheetLayout(bottomSheetLayout);
                myFragment.show(getSupportFragmentManager(), R.id.bottomsheet);
    

    Project is now available on GitHub:

    https://github.com/AndroidDeveloperLB/ThreePhasesBottomSheet

    I hope it doesn't have any bugs.


    The solution has bugs, sadly, so I won't mark this answer as the correct one:

    1. It only works well on Android 6 and above. Other have a weird behavior of showing the bottom sheet expanded for a tiny fraction of a time, each time when showing it.
    2. Orientation changes do not save the state of the scrolling at all, so I've disabled it.
    3. Rare issue of being able to scroll inside the bottom sheet's content while it's still collapsed (at the bottom)
    4. If a keyboard was shown before, the bottom sheet might get to be full screen when trying to be peeked.

    If anyone can help with it, please do.


    For issue #1, I've tried adding a fix by setting the visibility to INVISIBLE when the bottom sheet isn't peeked yet, but it doesn't always work, especially if a keyboard is shown.


    For issue #1, I've found how to fix it, by just wrapping (in "fragment_my.xml") the CoordinatorLayout with any view that you wish to use (I used FrameLayout), and also put a full-sized view in it (I just put "View") , as such:

    
        
        
    
        <...CollapsingToolbarLayout 
        ...
    

    It probably confused the bottomSheet when I had the CoordinatorLayout being its view. I've updated the project, but still, if there is any way to have a nicer solution, I'd like to know about it.


    In recent months, Google has published its own bottomSheet class, but as I've found it has a lot of issues, so I can't even try it out.

提交回复
热议问题