Android - Frame layout height not matching with co

2019-04-05 08:01发布

问题:

I have a problem with my FrameLayout (Container in Drawer Layout). The height of the FrameLayout exceeds the screen height (below the android default menu buttons at bottom).

<android.support.design.widget.CoordinatorLayout
        android:id="@+id/main_content"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">

        <android.support.design.widget.AppBarLayout
            android:id="@+id/navContainer"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:minHeight="?attr/actionBarSize"
                app:layout_scrollFlags="scroll|enterAlways" />

        </android.support.design.widget.AppBarLayout>

        <FrameLayout
            android:id="@+id/container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />

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

回答1:

My first attempt was to set a android:layout_marginBottom="?attr/actionBarSize" at the FrameLayout. This solved the solution for non-scrollable views having a "fixed" height in terms of no vertically scrollable content (like a usual RelativeLayout with match_parent height). Aligning a component to the parent bottom (android:layout_alignParentBottom="true") results in a still visible element. In Android Studio's Previewer the no exceeding of the height is visible.

However, this marginBotton-fix introduces a new problem for fragments whose root view is scrollable (like a RecyclerView). For these views when scrolling down the bottom margin will become visible in a white bar (in case white is the background color). This seams reasonable, as for those views the nested scrolling feature will slide out the toolbar

tl;dr I worked around that issue by applying the the ?attr/actionBarSize as bottom margin to non-scrollable fragments that are shown inside the Framelayout. Prior to that I set the height of the toolbar to be ?attr/actionBarSize.

Activity layout:

        <android.support.design.widget.AppBarLayout
            android:id="@+id/navContainer"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_scrollFlags="scroll|enterAlways" />

        </android.support.design.widget.AppBarLayout>

        <FrameLayout
                android:id="@+id/container"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:layout_behavior="@string/appbar_scrolling_view_behavior"
        />

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

Fragment layout:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:layout_marginBottom="?attr/actionBarSize"
          android:orientation="vertical">
          <!-- Further stuff here -->
          <TextView android:id="@+id/label"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_alignParentBottom="true"
          />
  </LinearLayout>

The only downside I faced right now is the white space to be shown in Android Studio's Previewer while creating the fragment layout.



回答2:

If you use different Fragments inside your CoordinatorLayout you will face the problem, that some Fragments have scrollable content and some should not scroll. Your Toolbar has the scrolling flags "scroll|enterAlways", which is ok for the former layouts, but not ok for the latter. My solution is a custom AppBarLayout.Behavior which switches the scrolling flags dependant on the custom tag (contentShouldNotScrollTag). Set this tag for the layouts, which should not scroll like this:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:tag="@string/contentShouldNotScrollTag">
   <!-- my non-scrollable Fragment layout -->
</FrameLayout>

As the result, the height of this Fragment will not exceed the screen's height. Here is the custom behavior class for the AppBarLayout:

public class MyScrollBehavior extends AppBarLayout.Behavior {
    private View content;

    public MyScrollBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onMeasureChild(CoordinatorLayout parent, AppBarLayout appBarLayout, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
        if(content == null) {
            content = parent.findViewById(R.id.container);
        }

        if(content != null) {
            boolean shouldNotScroll = content.findViewWithTag(parent.getContext().getString(R.string.contentShouldNotScrollTag)) != null;
            Toolbar toolbar = (Toolbar) appBarLayout.findViewById(R.id.toolbar);
            AppBarLayout.LayoutParams params =
                    (AppBarLayout.LayoutParams) toolbar.getLayoutParams();
            if (shouldNotScroll) {
                params.setScrollFlags(0);
                appBarLayout.setExpanded(true, true);
            } else {
                params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL
                        | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS);
            }
        }

        return super.onMeasureChild(parent, appBarLayout, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
    }
}