windowSoftInputMode ="adjustResize"不适用于半透明动作/导航栏

fab*_*bru 117 android resize statusbar window-soft-input-mode android-4.4-kitkat

我在新的Android KitKat(4.4)中使用半透明操作栏/导航栏时出现问题windowSoftInputMode="adjustResize".

Normaly将InputMode更改为adjustResize,应用程序应该在键盘显示时自行调整大小......但是在这里它不会!如果我删除透明效果的行,则调整大小正常.

因此,如果键盘可见,我的ListView就在它下面,我无法访问最后几个项目.(只能手动隐藏键盘)

AndroidManifest.xml中

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="XYZ"
android:versionCode="23"
android:versionName="0.1" >

<uses-sdk
    android:minSdkVersion="9"
    android:targetSdkVersion="19" />

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/Theme.XYZStyle" >
    <activity
        android:name="XYZ"
        android:label="@string/app_name"
        android:windowSoftInputMode="adjustResize" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

</manifest>
Run Code Online (Sandbox Code Playgroud)

值-V19/styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

<style name="Theme.XYZStyle" parent="@style/Theme.AppCompat.Light">
    <item name="android:windowTranslucentStatus">true</item>
    <item name="android:windowTranslucentNavigation">true</item>
</style>

</resources>
Run Code Online (Sandbox Code Playgroud)

fragment.xml之

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<ListView
    android:id="@+id/listView_contacts"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    android:divider="@null"
    android:dividerHeight="0dp"
    android:drawSelectorOnTop="true"
    android:fastScrollAlwaysVisible="true"
    android:fastScrollEnabled="true"
    android:paddingBottom="@dimen/navigationbar__height" >
</ListView>

</RelativeLayout>
Run Code Online (Sandbox Code Playgroud)

有没有想法解决这个问题?

pab*_*sco 168

您缺少以下属性:

android:fitsSystemWindows="true"
Run Code Online (Sandbox Code Playgroud)

片段 .xml布局的根目录RelativeLayout中.

更新:

去年Chris Bane发表了一篇有趣的演讲,详细解释了这是如何工作的:

https://www.youtube.com/watch?v=_mGDMVRO3iE

  • 我想这是全屏政策的一部分 (4认同)
  • @David它还没有修复,仍然在棉花糖设备中打破,如果你打开一个对话框并尝试滚动,那么softkeboard会阻止滚动 (4认同)
  • 它有效,但与我的工具栏和状态栏自定义冲突 (4认同)
  • 可以,但是状态栏不再透明。我希望布局可以覆盖整个屏幕。 (2认同)

kco*_*ock 32

有一个相关的bug报告在这里.我找到了一种解决方法,从有限的测试来看,似乎没有任何影响.ViewGroup使用FrameLayout下面的逻辑添加根的自定义实现(我几乎总是使用,所以这是我测试过的).然后,使用此自定义布局代替根布局,并确保进行设置android:fitsSystemWindows="true".然后,您可以getInsets()在布局后随时调用(例如添加一个OnPreDrawListener)来调整布局的其余部分,以便根据需要考虑系统插入.

import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import org.jetbrains.annotations.NotNull;

/**
 * @author Kevin
 *         Date Created: 3/7/14
 *
 * https://code.google.com/p/android/issues/detail?id=63777
 * 
 * When using a translucent status bar on API 19+, the window will not
 * resize to make room for input methods (i.e.
 * {@link android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE} and
 * {@link android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_PAN} are
 * ignored).
 * 
 * To work around this; override {@link #fitSystemWindows(android.graphics.Rect)},
 * capture and override the system insets, and then call through to FrameLayout's
 * implementation.
 * 
 * For reasons yet unknown, modifying the bottom inset causes this workaround to
 * fail. Modifying the top, left, and right insets works as expected.
 */
public final class CustomInsetsFrameLayout extends FrameLayout {
    private int[] mInsets = new int[4];

    public CustomInsetsFrameLayout(Context context) {
        super(context);
    }

    public CustomInsetsFrameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomInsetsFrameLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public final int[] getInsets() {
        return mInsets;
    }

    @Override
    protected final boolean fitSystemWindows(@NotNull Rect insets) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            // Intentionally do not modify the bottom inset. For some reason, 
            // if the bottom inset is modified, window resizing stops working.
            // TODO: Figure out why.

            mInsets[0] = insets.left;
            mInsets[1] = insets.top;
            mInsets[2] = insets.right;

            insets.left = 0;
            insets.top = 0;
            insets.right = 0;
        }

        return super.fitSystemWindows(insets);
    }
}
Run Code Online (Sandbox Code Playgroud)

由于fitSystemWindows已弃用,请参阅以下答案以完成解决方法.


小智 26

@kcoppock的回答非常有用,但是在API级别20中不推荐使用fitSystemWindows

因此,自API 20(KITKAT_WATCH)以来,您应该覆盖onApplyWindowInsets

@Override
public final WindowInsets onApplyWindowInsets(WindowInsets insets) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
        return super.onApplyWindowInsets(insets.replaceSystemWindowInsets(0, 0, 0,
                insets.getSystemWindowInsetBottom()));
    } else {
        return insets;
    }
}
Run Code Online (Sandbox Code Playgroud)


Her*_*man 11

这对我来说在片段中有半透明状态栏和adjustResize:

  1. 将自定义RelativeLayout设为@ Victor91和@kcoppock说.

  2. 使用CustomRelativeLayout作为片段的父布局.

  3. 用android声明主题:windowTranslucentStatus = true

  4. 必须使用android:windowSoftInputMode ="adjustResize"在Manifest中声明容器Activity并使用声明的主题

  5. 请在片段根布局上使用fitsSystemWindows!

    public class CustomRelativeLayout extends RelativeLayout {
    
        private int[] mInsets = new int[4];
    
        public CustomRelativeLayout(Context context) {
            super(context);
        }
    
        public CustomRelativeLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public CustomRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        public CustomRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
        }
    
        @Override
        public final WindowInsets onApplyWindowInsets(WindowInsets insets) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
                mInsets[0] = insets.getSystemWindowInsetLeft();
                mInsets[1] = insets.getSystemWindowInsetTop();
                mInsets[2] = insets.getSystemWindowInsetRight();
                return super.onApplyWindowInsets(insets.replaceSystemWindowInsets(0, 0, 0,
                        insets.getSystemWindowInsetBottom()));
            } else {
                return insets;
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

然后在xml中,

<com.blah.blah.CustomRelativeLayout 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">
</com.blah.blah.CustomRelativeLayout>
Run Code Online (Sandbox Code Playgroud)


Vic*_*ina 8

如果要自定义插图,并且目标API级别> = 21,则可以完成此操作而不必创建自定义视图组。通过仅设置fitsSystemWindows填充,默认情况下会将填充应用于您的容器视图,这可能是您不希望的。

版本检查内置于此方法中,只有> = 21的设备才会在lambda中执行代码。Kotlin示例:

ViewCompat.setOnApplyWindowInsetsListener(container) { view, insets ->
  insets.replaceSystemWindowInsets(0, 0, 0, insets.systemWindowInsetBottom).apply {
    ViewCompat.onApplyWindowInsets(view, this)
  }
}
Run Code Online (Sandbox Code Playgroud)

确保您的布局仍然设置该fitsSystemWindows标志,否则将不会调用窗口插入侦听器。

<FrameLayout
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    />
Run Code Online (Sandbox Code Playgroud)

这些来源很有帮助:

https://medium.com/google-developers/why-would-i-want-to-fitssystemwindows-4e26d9ce1eec https://medium.com/@azizbekian/windowinsets-24e241d4afb9


小智 6

首先将其添加到根布局中。

android:fitsSystemWindows="true"
Run Code Online (Sandbox Code Playgroud)

当您使用此方法时,您有责任确保应用程序 UI 的关键部分(例如,地图应用程序中的内置控件)最终不会被系统栏覆盖。这可能会使您的应用程序无法使用。在大多数情况下,您可以通过将 android:fitsSystemWindows 属性添加到 XML 布局文件中并设置为 true 来处理此问题。这会调整父 ViewGroup 的填充,以为系统窗口留出空间。这对于大多数应用程序来说已经足够了。

但是,在某些情况下,您可能需要修改默认填充以获得应用程序所需的布局。要直接操纵内容相对于系统栏(占据称为窗口“内容插图”的空间)的布局方式,请重写 fitSystemWindows(Rect insets)。当窗口的内容插入发生更改时,视图层次结构将调用 fitSystemWindows() 方法,以允许窗口相应地调整其内容。通过重写此方法,您可以根据需要处理插图(以及应用程序的布局)。

https://developer.android.com/training/system-ui/status#behind

如果你想成为一名窗户装配大师,请观看来自android开发者的视频。 https://www.youtube.com/watch?v=_mGDMVRO3iE


ara*_*aks 5

我有同样的问题,我的活动有一个ScrollView作为根视图和半透明状态栏激活它没有正确调整大小键盘显示...并且因此屏幕没有滚动隐藏输入视图.

解决方案:将所有内容(布局和活动逻辑)移动到新的片段中.然后将Activity更改为仅包含此Fragment.现在一切都按预期工作!

这是活动的布局:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"

    android:id="@+id/contentView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true" />
Run Code Online (Sandbox Code Playgroud)


Oni*_*nik 5

由和方法弃用引起的有用@Victor Rendina答案的小更新。replaceSystemWindowInsetssystemWindowInsetBottom

先决条件:

  • API >= 21
  • implementation 'androidx.core:core-ktx:1.5.0-alpha02' 至少

科特林扩展:

fun View?.fitSystemWindowsAndAdjustResize() = this?.let { view ->
    ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets ->
        view.fitsSystemWindows = true
        val bottom = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom

        WindowInsetsCompat
            .Builder()
            .setInsets(
                WindowInsetsCompat.Type.systemBars(),
                Insets.of(0, 0, 0, bottom)
            )
            .build()
            .apply {
                ViewCompat.onApplyWindowInsets(v, this)
            }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

rootView.fitSystemWindowsAndAdjustResize()
Run Code Online (Sandbox Code Playgroud)

哪里rootView是布局的根视图:)

注: 如果扩展不为你的根视图的工作(我有当遇到了这个ConstraintLayout作为rootView一个包住整个布局)FrameLayout,以便FrameLayout成为新的根视图