【问题标题】:fitsSystemWindows="true" doesn't work after calling setContentView()调用 setContentView() 后,fitsSystemWindows="true" 不起作用
【发布时间】:2017-01-31 11:16:13
【问题描述】:

对于我正在开发的应用程序,我想在用户输入后重新加载 UI(基本上是在他们对其进行更改后完全重置它)。我想尝试避免破坏/重新创建活动并改用setContentView(),因为它要快得多。

但是,当我这样做时,我遇到了一个问题:新创建的 UI 不尊重 fitsSystemWindows="true" 并且它的一部分最终位于 android 的状态栏后面。

我设法把它归结为那个代码示例来测试它:

layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/mainContainer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">
    <Button
        android:text="Button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/button" />
 </LinearLayout>

MainActivity.java

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout);

        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                reloadUI();
            }
        });

    }

    public void reloadUI() {
        setContentView(R.layout.layout);
    }
}

当我加载应用程序时,我得到了预期的布局,即屏幕顶部的一个简单按钮,就在状态栏的正下方:

但是,一旦我再次单击调用 setContentView 的按钮(显示相同的 XML),按钮就会出现在状态栏后面:

调用mainContainer.getMeasuredHeight() 来检查会发生什么在应用程序的第一次启动时给了我 1848px(在一个 1920px 高的屏幕上,所以它的高度比整个屏幕小 72px,72px 是状态栏的高度) ,但是一旦我再次调用 setContentView,mainContainer.getMeasuredHeight() 会给我 1920px。

我在这里遗漏了什么吗?我可以强制 mainContainer 保持 1848px 的高度和 72px 的顶部填充,但我更愿意避免像这样丑陋的 hack。

【问题讨论】:

  • 你为什么又打电话给setContentView?相反,您可以invalidate 整个viewgroup
  • 我试过了,但它并没有正确重置所有内容。例如,在我的用例中,用户可以将一些自定义视图设置为特定颜色(存储在自定义视图类中),并且在调用无效时不会重置为默认值,它只是重绘 UI。我可以重构我的应用程序的一部分以正确处理无效,但我认为使用 setContentView 可以更快地重新开始并将 UI 重新加载到默认状态。

标签: android android-layout android-window


【解决方案1】:

所以,您需要让框架再次将WindowInsets 分派到您的根视图。这正是ViewCompat.requestApplyInsets(View) 要做的事情:

请求执行新的View.onApplyWindowInsets(WindowInsets) 调度。这会退回到View.requestFitSystemWindows()(如果有)。

只需应用一行即可解决您的所有问题:

public void reloadUI() { setContentView(R.layout.layout); // `R.id.mainContainer` is the id of the root view in `R.layout.layout` ViewCompat.requestApplyInsets(findViewById(R.id.mainContainer)); }

【讨论】:

  • 具有足够简单信息的完美解决方案。当我找到的所有其他解决方案都失败时,这个解决方案立即生效,没有出现任何并发症。
【解决方案2】:

我遇到了同样的问题。我的解决方案是手动更改rootViewmarginToppaddingTop以适应View

【讨论】:

    猜你喜欢
    • 2012-02-15
    • 1970-01-01
    • 1970-01-01
    • 2022-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-29
    相关资源
    最近更新 更多