我有SingleFramgnetActivity
,其目的只是保留和替换其中的片段。
布局如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
tools:context=".SingleFragmentActivity"
>
<include layout="@layout/toolbar"/>
<FrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
我正在替换FrameLayout中的Fragments
。当我在fitsSystemWindows
布局上将Fragment
设置为true时,它没有响应。实际上它仅在创建Activity
时有效,但是当我替换Fragment
内的FrameLayout
后,fitsSystemWindows
参数将被忽略,布局位于状态栏下方导航栏。
我找到了一些solution自定义FrameLayout,它使用了弃用的方法,但由于某种原因它不适用于我(与普通FrameLayout相同的结果)我也不喜欢使用弃用方法的想法。
答案 0 :(得分:8)
您的FrameLayout
不知道窗口插入大小,因为它的父级 - LinearLayout
尚未发送任何内容。作为一种变通方法,您可以继承LinearLayout
并将插件传递给子项:
@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
int childCount = getChildCount();
for (int index = 0; index < childCount; index++)
getChildAt(index).dispatchApplyWindowInsets(insets); // let children know about WindowInsets
return insets;
}
您可以查看my this答案,其中将详细说明其工作原理,以及如何使用ViewCompat.setOnApplyWindowInsetsListener
API。
答案 1 :(得分:3)
您还可以构建自定义decltype
并使用WindowInsetsFrameLayout
请求再次应用插入内容:
OnHierarchyChangedListener
答案 2 :(得分:1)
我认为问题围绕着onApplyWindowInsets
在片段视图层次结构被附加之前被调用。一种有效的解决方案是在片段的视图层次结构中的某个视图上获得以下覆盖。
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
// force window insets to get re-applied if we're being attached by a fragment.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
requestApplyInsets();
} else {
//noinspection deprecation
requestFitSystemWindows();
}
}
下面是完整的解决方案(如果您不必使用CoordinatorLayout
)。确保在层次结构中更高的视图中fitSystemWindows=true
不会出现。也许不是别的地方。我怀疑(但不确定)consumeSystemWindowInsets
是否会在视图树的布局顺序中进一步查看视图的插图。
package com.twoplay.xcontrols;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.view.WindowInsets;
import android.widget.FrameLayout;
public class FitSystemWindowsLayout extends FrameLayout {
private boolean mFit = true;
public FitSystemWindowsLayout(final Context context) {
super(context);
init();
}
public FitSystemWindowsLayout(final Context context, final AttributeSet attrs) {
super(context, attrs);
init();
}
public FitSystemWindowsLayout(final Context context, final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setFitsSystemWindows(true);
}
public boolean isFit() {
return mFit;
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
requestApplyInsets();
} else {
//noinspection deprecation
requestFitSystemWindows();
}
}
public void setFit(final boolean fit) {
if (mFit == fit) {
return;
}
mFit = fit;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
requestApplyInsets();
} else {
//noinspection deprecation
requestFitSystemWindows();
}
}
@SuppressWarnings("deprecation")
@Override
protected boolean fitSystemWindows(final Rect insets) {
if (mFit) {
setPadding(
insets.left,
insets.top,
insets.right,
insets.bottom
);
return true;
} else {
setPadding(0, 0, 0, 0);
return false;
}
}
@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
@Override
public WindowInsets onApplyWindowInsets(final WindowInsets insets) {
if (mFit) {
setPadding(
insets.getSystemWindowInsetLeft(),
insets.getSystemWindowInsetTop(),
insets.getSystemWindowInsetRight(),
insets.getSystemWindowInsetBottom()
);
return insets.consumeSystemWindowInsets();
} else {
setPadding(0, 0, 0, 0);
return insets;
}
}
}
怀疑,而不是事实:整个层次结构中只有一个视图有机会吃掉窗口插入物,除非你在层次结构中有CoordinatorLayout
,这允许多个直接孩子拥有{{1} }。如果你有一个CoordinatorLayout,你的里程可能会有所不同。
Android中的这整个功能似乎是一个不圣洁的混乱。
答案 3 :(得分:0)
a)您可以将CoordinatorLayout用作片段内的根视图
或
b)您可以创建自定义线性布局,将其称为requestApplyInsets并将其用作片段内的根视图
class WindowInsetsLinearLayout : LinearLayout {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
override fun onAttachedToWindow() {
super.onAttachedToWindow()
ViewCompat.requestApplyInsets(this)
}
}
然后在片段中可以捕获应用的内嵌
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
ViewCompat.setOnApplyWindowInsetsListener(root_layout) { _, insets ->
//appbar.setPadding(insets.systemWindowInsetLeft, insets.systemWindowInsetTop, 0, 0)
insets.consumeSystemWindowInsets()
}
}