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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21092888/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 03:58:23  来源:igfitidea点击:

windowSoftInputMode="adjustResize" not working with translucent action/navbar

androidresizestatusbarandroid-4.4-kitkatwindow-soft-input-mode

提问by fabianbru

I have problems with the translucent actionbar/navbar in the new Android KitKat (4.4) and the windowSoftInputMode="adjustResize".

我在新的 Android KitKat (4.4) 和windowSoftInputMode="adjustResize".

Normaly changing the InputMode to adjustResize, the app should resize itself when keyboard is shown... but here it won't! If I delete the lines for the transparent effect, the resize is working.

通常将 InputMode 更改为 adjustResize,应用程序应在显示键盘时自行调整大小……但在这里不会!如果我删除透明效果的线条,则调整大小有效。

So if the keyboard is visible, my ListView is under it and I can't access the last few items. (Only by hiding the keyboard manually)

所以如果键盘是可见的,我的 ListView 就在它下面,我无法访问最后几个项目。(只能通过手动隐藏键盘)

AndroidManifest.xml

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>

values-v19/styles.xml

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

fragment.xml

片段.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>

Anyone ideas for fixing this?

任何解决这个问题的想法?

回答by pablisco

You are missing the following property:

您缺少以下属性:

android:fitsSystemWindows="true"

in the root RelativeLayoutof the fragment.xml layout.

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

Update:

更新:

Last year there was an interesting talk by Chris Bane that explains in good detail how this works:

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

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

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

回答by Kevin Coppock

There's a related bug report here. I've found a workaround that, from limited testing, seems to do the trick with no repercussions. Add a custom implementation of your root ViewGroup(I almost always am using FrameLayout, so this is what I've tested with) with the logic below. Then, use this custom layout in place of your root layout, and ensure you set android:fitsSystemWindows="true". You can then just call getInsets()any time after layout (e.g. add an OnPreDrawListener) to adjust the rest of your layout to account for the system insets, if desired.

有一个相关的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);
    }
}

Since fitSystemWindows was deprecated, please refer to the answer below to complete the workaround.

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

回答by Victor91

@kcoppock answer is really helpful, but fitSystemWindows was deprecated in API level 20

@kcoppock 的回答真的很有帮助,但在 API 级别 20 中不推荐使用 fitSystemWindows

So since API 20 (KITKAT_WATCH) you should override onApplyWindowInsets

所以从 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;
    }
}

回答by Herman

This worked for me to have translucent status bar and adjustResize in fragment:

这对我有半透明的状态栏和片段中的 adjustResize 有用:

  1. Make a custom RelativeLayout as @Victor91 and @kcoppock said.

  2. Use CustomRelativeLayout as parent layout for your fragment.

  3. Declare theme with android:windowTranslucentStatus = true

  4. The container Activity must be declared in Manifest with android:windowSoftInputMode="adjustResize" and use the declared theme

  5. Please Use fitsSystemWindows on fragment root layout!

    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;
            }
        }
    }
    
  1. 像@Victor91 和@kcoppock 所说的那样制作一个自定义的RelativeLayout。

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

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

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

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

Then in xml,

然后在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>

回答by Victor Rendina

If you want to customize the insets and you are targeting API level >=21 you can accomplish this without having to create a custom view group. By just setting fitsSystemWindowspadding will be applied to your container view by default, which you may not want.

如果您想自定义插图并且您的目标是 API 级别 >=21,则无需创建自定义视图组即可完成此操作。通过设置fitsSystemWindows填充将默认应用于您的容器视图,您可能不想要。

The version checks are built into this method and only devices >= 21 will execute the code inside the lambda. Kotlin example:

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

ViewCompat.setOnApplyWindowInsetsListener(container) { view, insets ->
  insets.replaceSystemWindowInsets(0, 0, 0, insets.systemWindowInsetBottom).apply {
    ViewCompat.onApplyWindowInsets(view, this)
  }
}

Make sure your layout still sets the fitsSystemWindowsflag otherwise the window insets listener will not be called.

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

<FrameLayout
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    />

These sources are helpful:

这些来源很有帮助:

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

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

回答by araks

I had the same problem, My Activity had a ScrollView as root view and with translucent statusbar activated it didn't resize correctly when keyboard showed... and conseguently the screen didn't scrolled hiding the input views.

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

Solution: Moved everything (layout and activity logic) inside a new Fragment. Then changed the Activity to only include this Fragment. Now everything works as expected!

解决方案:将所有内容(布局和活动逻辑)移到新 Fragment 中。然后将 Activity 更改为仅包含此 Fragment。现在一切正常!

This is the layout of the activity:

这是活动的布局:

<?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" />

回答by Loyea

Based on Joseph Johnson's workaround in Android How to adjust layout in Full Screen Mode when softkeyboard is visible

基于 Joseph Johnson 在Android 中的解决方法如何在软键盘可见时在全屏模式下调整布局

call this in onCreate()after setContentView()in your activity.

称这种现象onCreate()setContentView()您的活动。

AndroidBug5497Workaround.assistActivity(this);

AndroidBug5497Workaround.assistActivity(this);

a litte different from original replace return (r.bottom - r.top);with return r.bottom;in computeUsableHeight()

与原来的有点不同,替换return (r.bottom - r.top);return r.bottom;incomputeUsableHeight()

for some reason, i must set my activity fitsSystemWindowsattribute to false.

出于某种原因,我必须将我的活动fitsSystemWindows属性设置为false.

this workaround saved me. it's works well for me. hope can help you.

这个解决方法救了我。它对我很有效。希望能帮到你。

the implementation class is:

实现类是:

public class AndroidBug5497Workaround {

// For more information, see https://code.google.com/p/android/issues/detail?id=5497
// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.

public static void assistActivity (Activity activity) {
    new AndroidBug5497Workaround(activity);
}

private View mChildOfContent;
private int usableHeightPrevious;
private FrameLayout.LayoutParams frameLayoutParams;

private AndroidBug5497Workaround(Activity activity) {
    FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
    mChildOfContent = content.getChildAt(0);
    mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        public void onGlobalLayout() {
            possiblyResizeChildOfContent();
        }
    });
    frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
}

private void possiblyResizeChildOfContent() {
    int usableHeightNow = computeUsableHeight();
    if (usableHeightNow != usableHeightPrevious) {
        int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
        int heightDifference = usableHeightSansKeyboard - usableHeightNow;
        if (heightDifference > (usableHeightSansKeyboard/4)) {
            // keyboard probably just became visible
            frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
        } else {
            // keyboard probably just became hidden
            frameLayoutParams.height = usableHeightSansKeyboard;
        }
        mChildOfContent.requestLayout();
        usableHeightPrevious = usableHeightNow;
    }
}

private int computeUsableHeight() {
    Rect r = new Rect();
    mChildOfContent.getWindowVisibleDisplayFrame(r);
    return r.bottom;
}

}

回答by RESTfulGeoffrey

It shouldn't work with the translucent status bar; that setting forces the window into fullscreen mode which does not work with adjustResize.

它不应该与半透明状态栏一起使用;该设置强制窗口进入全屏模式,该模式不适用于 adjustResize。

You can either use adjustPan or use the fitsSystemWindows properties. I would suggest reading about the feature though, it has significant side effects:

您可以使用 adjustPan 或使用 fitsSystemWindows 属性。不过,我建议阅读有关该功能的信息,它有显着的副作用:

https://medium.com/google-developers/why-would-i-want-to-fitssystemwindows-4e26d9ce1eec

https://medium.com/google-developers/why-would-i-want-to-fitssystemwindows-4e26d9ce1eec

回答by Tr?n Thanh Phong

  • After I had researched on all forum. thoese ways can not help find point out. Lucky when i tried doing this way. It helps me resolved problem
  • 在我研究了所有论坛之后。这些方法不禁找出来点。幸运的是,当我尝试这样做时。它帮助我解决了问题

XML

XML

<RelativeLayout 
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:fitsSystemWindows="true">
       <!-- Your xml -->
    </RelativeLayout>

Activity

活动

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView("Your Activity");
   setAdjustScreen();

}

Created Func

创建函数

protected void setAdjustScreen(){
        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
        /*android:windowSoftInputMode="adjustPan|adjustResize"*/
}

Finally adding some lines to your mainifest

最后在你的 mainifest 添加一些行

 <activity
     android:name="Your Activity"
     android:windowSoftInputMode="adjustPan|adjustResize"
     android:screenOrientation="portrait"></activity>

回答by gaurav gupta

I had the same problem. I have solved using coordinatorlayout

我有同样的问题。我已经使用 coordinatorlayout 解决了

activity.main.xml

活动.main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    android:layout_height="match_parent" android:layout_width="match_parent"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">


    <android.support.design.widget.AppBarLayout
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:theme="@style/AppTheme.AppBarOverlay">

    <android.support.v7.widget.Toolbar
        android:layout_height="?attr/actionBarSize"
        android:layout_width="match_parent"
        app:popupTheme="@style/AppTheme.PopupOverlay"
        android:background="?attr/colorPrimary"
        android:id="@+id/toolbar"/>

</android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main2"/>

</android.support.design.widget.CoordinatorLayout>

content_main2.xml

content_main2.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">


    <android.support.v7.widget.RecyclerView
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:layout_marginTop="30dp"
        android:layout_marginBottom="30dp"
        app:layout_scrollFlags="scroll|exitUntilCollapsed"
        android:id="@+id/post_msg_recyclerview">
    </android.support.v7.widget.RecyclerView>

    <EditText
        android:layout_width="match_parent"
        android:layout_height="50dp"
        app:layout_constraintBottom_toBottomOf="parent"
        android:background="@color/colorPrimary"


        />

</android.support.constraint.ConstraintLayout>

MainActivity.java

主活动.java

now add this line linearLayoutManager.setStackFromEnd(true);

现在添加这一行 linearLayoutManager.setStackFromEnd(true);

 LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        linearLayoutManager.setStackFromEnd(true);
        recyclerView.setLayoutManager(linearLayoutManager);
        Adapter adapter1=new Adapter(arrayList);
        recyclerView.setAdapter(adapter1);