我有一个带有导航抽屉和全出血碎片的活动(顶部的图像必须出现在Lollipop上的半透明系统栏后面)。虽然我有一个临时解决方案,其中片段通过简单地在Activity的XML中使用<fragment>
标记来膨胀,但它看起来很好。
然后我不得不用<fragment>
替换<FrameLayout>
并执行片段事务,现在片段不再出现在系统栏后面,尽管fitsSystemWindows
设置为true
跨越所有必需的层次结构。
我认为<fragment>
在Activity的布局中与其自身的膨胀之间可能存在一些差异。我用Google搜索并为KitKat找到了一些解决方案,但这些解决方案都不适用于我(Lollipop)。
activity.xml
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:fitsSystemWindows="true">
<FrameLayout
android:id="@+id/fragment_host"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
</FrameLayout>
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_gravity="start"
android:fitsSystemWindows="true"/>
</android.support.v4.widget.DrawerLayout>
fragment.xml之
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="224dp"
android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
...
activity.xml 就是这样的:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:fitsSystemWindows="true">
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/fragment"
android:name="com.actinarium.random.ui.home.HomeCardsFragment"
tools:layout="@layout/fragment_home"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_gravity="start"
android:fitsSystemWindows="true"/>
</android.support.v4.widget.DrawerLayout>
答案 0 :(得分:15)
我的问题与您的问题类似:我有底栏导航,它正在替换内容片段。现在,有些片段想要在状态栏上绘制(使用CoordinatorLayout
,AppBarLayout
),而其他片段则不是(使用ConstraintLayout
,Toolbar
)。
ConstraintLayout
FrameLayout
[the ViewGroup of your choice]
BottomNavigationView
ianhanniballake添加另一个CoordinatorLayout
图层的建议不是我想要的,所以我创建了一个自定义FrameLayout
来处理插图(就像他建议的那样),过了一段时间我遇到了这个解决方案,实际上代码不多:
activity_main.xml中
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.app.WindowInsetsFrameLayout
android:id="@+id/fragment_container"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/bottom_navigation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<BottomNavigationView
android:id="@+id/bottom_navigation"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</android.support.constraint.ConstraintLayout>
WindowInsetsFrameLayout.java
/**
* FrameLayout which takes care of applying the window insets to child views.
*/
public class WindowInsetsFrameLayout extends FrameLayout {
public WindowInsetsFrameLayout(Context context) {
this(context, null);
}
public WindowInsetsFrameLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public WindowInsetsFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// Look for replaced fragments and apply the insets again.
setOnHierarchyChangeListener(new OnHierarchyChangeListener() {
@Override
public void onChildViewAdded(View parent, View child) {
requestApplyInsets();
}
@Override
public void onChildViewRemoved(View parent, View child) {
}
});
}
}
答案 1 :(得分:3)
好的,在几个人指出fitsSystemWindows
的工作方式不同之后,不应该在层次结构的每个视图中使用它,我继续尝试并从不同的视图中删除属性。
从fitsSystemWindows
= \
activity.xml
后,我获得了预期的状态
答案 2 :(得分:1)
我去年创建了这个来解决这个问题:https://gist.github.com/cbeyls/ab6903e103475bd4d51b
编辑:确保您首先了解适合SystemSindows的功能。当您在View上设置它时,它基本上意味着:&#34;将此视图及其所有子项放在状态栏下方和导航栏上方#34;。在顶部容器上设置此属性是没有意义的。
答案 3 :(得分:1)
用Kotlin编写的另一种方法,
问题:
您使用的FrameLayout
不会传播fitsSystemWindows="true"
到他的孩子:
<FrameLayout
android:id="@+id/fragment_host"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true" />
解决方案:
扩展FrameLayout
类并覆盖函数onApplyWindowInsets()
,以将窗口插图传播到附加的片段:
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
class BetterFrameLayout : FrameLayout {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)
override fun onApplyWindowInsets(windowInsets: WindowInsets): WindowInsets {
childCount.let {
// propagates window insets to children's
for (index in 0 until it) {
getChildAt(index).dispatchApplyWindowInsets(windowInsets)
}
}
return windowInsets
}
}
将此布局用作片段容器,而不是标准FrameLayout
:
<com.foo.bar.BetterFrameLayout
android:id="@+id/fragment_host"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true" />
其他:
如果您想进一步了解此结帐Chris Banes博客文章Becoming a master window fitter。
答案 4 :(得分:1)
分配窗口插图的另一个可怕的问题是,在深度优先搜索中,第一个使用窗口插图的视图会阻止层次结构中的所有其他视图看到窗口插图。
以下代码片段允许多个孩子处理窗口插图。如果您尝试将窗口插图应用于NavigationView(或CoordinatorLayout)外部的装饰,则非常有用。覆盖您选择的ViewGroup。
@Override
public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
if (!insets.isConsumed()) {
// each child gets a fresh set of window insets
// to consume.
final int count = getChildCount();
for (int i = 0; i < count; i++) {
WindowInsets freshInsets = new WindowInsets(insets);
getChildAt(i).dispatchApplyWindowInsets(freshInsets);
}
}
return insets; // and we don't.
}
也有用:
@Override
public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
return insets.consume(); // consume without adding padding!
}
允许布局该视图子级的普通普通视图而没有窗口插入。