Android - 框架布局高度与协调器布局不匹配

时间:2015-09-18 11:02:28

标签: android height matching android-framelayout

我的FrameLayout(抽屉布局中的容器)有问题。 FrameLayout的高度超过了屏幕高度(在底部的android默认菜单按钮下方)。

<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

2 个答案:

答案 0 :(得分:6)

我的第一次尝试是在FrameLayout设置android:layout_marginBottom="?attr/actionBarSize"。这解决了具有“固定”高度的不可滚动视图的解决方案,其中没有可垂直滚动的内容(如具有match_parent高度的通常RelativeLayout)。将组件与父底部对齐(android:layout_alignParentBottom="true")会产生一个仍然可见的元素。在Android Studio的预览器中,可以看到不超过高度。

但是,这个marginBotton-fix为根视图可滚动的片段(如RecyclerView)引入了一个新问题。对于这些视图,当向下滚动时,底部边距将在白色条中可见(如果白色是背景颜色)。这种接缝合理,对于那些视图,嵌套滚动功能将滑出工具栏 ListView with last item cut

tl; dr 我通过将?attr/actionBarSize作为底部边距应用于Framelayout中显示的不可滚动的片段来解决该问题。在此之前,我将工具栏的高度设置为?attr/actionBarSize

活动布局:     

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

片段布局:

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

我现在唯一面临的缺点是在创建片段布局时,Android Studio预览器中会显示空白区域。

答案 1 :(得分:2)

如果您在Fragments内使用不同的CoordinatorLayout,则会遇到问题,因为某些Fragments具有可滚动内容,而某些Toolbar不应滚动。您的scroll|enterAlways具有滚动标记&#34; AppBarLayout.Behavior&#34;,这对于以前的布局是可以的,但对后者不适用。我的解决方案是自定义<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> ,它根据自定义标记(contentShouldNotScrollTag)切换滚动标记。为布局设置此标记,不应该像这样滚动:

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); } } 的自定义行为类:

public enum MyEnum {
    VALUE_1("Super"),
    VALUE_2("Rainbow"),
    VALUE_3("Dash"),
    VALUE_3("Rocks");

    private final String value;

    MyEnum(String value) {
        this.value = value;
    }

    /**
     * @return the Enum representation for the given string.
     * @throws IllegalArgumentException if unknown string.
     */
    public static MyEnum fromString(String s) throws IllegalArgumentException {
        return Arrays.stream(MyEnum.values())
                .filter(v -> v.value.equals(s))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("unknown value: " + s));
    }
}