Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android - Frame layout height not matching with coordinator layout

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>

Height exceeding as seen in Android Studio Designer

like image 633
Okn Avatar asked Sep 18 '15 11:09

Okn


2 Answers

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 ListView with last item cut

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.

like image 199
Capricorn Avatar answered Nov 16 '22 10:11

Capricorn


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);
    }
}
like image 2
artkoenig Avatar answered Nov 16 '22 10:11

artkoenig