“android:windowSoftInputMode="adjustResize"”没有起到任何作用?

31

我有一个使用以下布局的虚假对话框:

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

    <FrameLayout    android:id="@+id/dialogHolder"
                    android:layout_height="wrap_content"
                    android:layout_width="wrap_content"
                    android:padding="15dp"
                    android:layout_gravity="center"
                    android:background="@drawable/panel_picture_frame_bg_focus_blue"/>    
</FrameLayout> 

根据打开的对话框,我将一个片段放置在<FrameLayout>中 - 控制对话框的活动看起来像这样:

<activity
    android:label="@string/app_name"
    android:name=".activity.DialogActivity"
    android:theme="@style/CustomTheme.Screen.Transparent" 
    android:windowSoftInputMode="adjustResize">

不幸的是,当你在对话框中点击编辑文本时,不会发生任何缩放。无论是windowSoftInputMode还是pan模式,功能上没有任何区别。

文档中说“这当然仅适用于具有可调整大小区域以减少足够空间的应用程序”,但没有告诉你“可调整大小区域”是什么意思,并让我想到某种方式下我没有可调整大小区域?

如果有人知道情况,请帮忙解决一下吗?

编辑

像这样将对话框包围起来并没有改变任何东西:

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

    <View
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <FrameLayout    
        android:id="@+id/dialogHolder"
        android:layout_height="wrap_content"
    android:layout_width="wrap_content"
        android:padding="15dp"
        android:layout_gravity="center"
        android:background="@drawable/panel_picture_frame_bg_focus_blue"/>

    <View
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_weight="1" />
</LinearLayout>

编辑2

将ScrollView作为父级也没有帮助:

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

    <FrameLayout
            android:id="@+id/dialogHolder"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:padding="15dp" />

</ScrollView>

使用一个EditText进行检查。单击EditText内部以显示软键盘,现在您可以看到android:windowSoftInputMode=“adjustResize”的用法。如果使用adjustNothing,即使键盘显示,您的布局也不应更改。 - Padma Kumar
抱歉,我不明白您的意思。 - Graeme
9个回答

52

我创建了一个新项目,以尝试使窗口调整的基本功能正常工作,并将其逐步移向我的项目目标。在此过程中,我追踪到了问题所在:

在我的主题层次结构中,我有这个属性:

<item name="android:windowFullscreen">true</item> 

我的自定义主题的祖先被埋藏在 Theme.Black.NoTitleBar.FullScreen 级别下。

文档 表示这是一个“标志,指示此窗口是否应填充整个屏幕”。如果你有一个占据整个屏幕的应用程序,那么拥有这个功能听起来很不错...除非没有这个标志,该应用程序仍然会占据整个屏幕。

实际上,一旦你去掉了这个标志,在应用程序中根本没有任何变化...除了 adjustResize 现在可以完美地工作了。


7
谢谢这篇文章!但我想要全屏和调整大小的功能。:( - lippo
3
请再次阅读答案。无论 windowFullscreen 的值是 true、false 还是不存在,您的 Activity 都将是全屏的。 - Graeme
3
当我从自定义主题中删除android:windowFullscreen时,很遗憾它不再是全屏显示(适用于Android 4.1)。您可以发布您的主题的完整代码吗?也许在我的实现中有一些我忽略了的东西。 - Alexey
1
我会添加我的观察。Graeme关于android:windowFullscreen属性是正确的。它隐藏了状态栏(顶部带有时钟和通知等)。这样做的一个后果是,设置为adjustResize的android:windowSoftInputMode属性不起作用。当软键盘显示时,活动占用了所有可用空间,而且不知道一些空间被软键盘占用。因此,无法滚动到活动的底部。 - Anderson
有趣的是,这发生在较新的API上。我在API 19上进行了测试。 在API 10(2.3.5)的设备上,adjustResize有效。活动知道键盘占用了位置,并且可以在键盘可见的情况下滚动到底部。 顺便提一句:如果隐藏状态栏,则应该同时隐藏操作栏。 - Anderson
显示剩余5条评论

50

前段时间我在一个我创建的库中也遇到了同样的问题。(MaterialDrawer

据我所见,所有提供的答案都没有解决主要问题,它们只是指出要删除全屏标志(android:windowFullscreen),这对许多人来说并不是解决方案。

上述“问题”仅出现在Android版本从API Level 19(KITKAT)开始,因为它们改变了行为。准确地说,这不是问题,它正在按预期工作。请参见Android员工的评论(Android-Issue)。


因此,我开始挖掘Android源代码,并通过使用ViewTreeObserver.OnGlobalLayoutListener来实现以下解决方案,并在键盘显示/隐藏时做出反应。如果键盘被显示,我会将填充添加到容器视图的底部,这将模拟与adjustResize相同的效果。


解决方案

为了简化使用,我将整个过程封装在一个简单的KeyboardUtil帮助类中。

/**
 * Created by mikepenz on 14.03.15.
 * This class implements a hack to change the layout padding on bottom if the keyboard is shown
 * to allow long lists with editTextViews
 * Basic idea for this solution found here: https://dev59.com/WHI95IYBdhLWcg3wyRM0#9108219
 */
public class KeyboardUtil {
    private View decorView;
    private View contentView;

    public KeyboardUtil(Activity act, View contentView) {
        this.decorView = act.getWindow().getDecorView();
        this.contentView = contentView;

        //only required on newer android versions. it was working on API level 19 (Build.VERSION_CODES.KITKAT)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            decorView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);
        }
    }

    public void enable() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            decorView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);
        }
    }

    public void disable() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            decorView.getViewTreeObserver().removeOnGlobalLayoutListener(onGlobalLayoutListener);
        }
    }


    //a small helper to allow showing the editText focus
    ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            Rect r = new Rect();
            //r will be populated with the coordinates of your view that area still visible.
            decorView.getWindowVisibleDisplayFrame(r);

            //get screen height and calculate the difference with the useable area from the r
            int height = decorView.getContext().getResources().getDisplayMetrics().heightPixels;
            int diff = height - r.bottom;

            //if it could be a keyboard add the padding to the view
            if (diff != 0) {
                // if the use-able screen height differs from the total screen height we assume that it shows a keyboard now
                //check if the padding is 0 (if yes set the padding for the keyboard)
                if (contentView.getPaddingBottom() != diff) {
                    //set the padding of the contentView for the keyboard
                    contentView.setPadding(0, 0, 0, diff);
                }
            } else {
                //check if the padding is != 0 (if yes reset the padding)
                if (contentView.getPaddingBottom() != 0) {
                    //reset the padding of the contentView
                    contentView.setPadding(0, 0, 0, 0);
                }
            }
        }
    };


    /**
     * Helper to hide the keyboard
     *
     * @param act
     */
    public static void hideKeyboard(Activity act) {
        if (act != null && act.getCurrentFocus() != null) {
            InputMethodManager inputMethodManager = (InputMethodManager) act.getSystemService(Activity.INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(act.getCurrentFocus().getWindowToken(), 0);
        }
    }
}

然后您可以通过执行以下操作在您的活动或片段中使用它:

//initialize the KeyboardUtil (you can do this global)
KeyboardUtil keyboardUtil = new KeyboardUtil(activity, getContent().getChildAt(0));

//enable it
keyboardUtil.enable();

//disable it
keyboardUtil.disable();
整个util类在上述提到的库MaterialDrawer中使用,并且可以在此处找到KeyboardUtil。这将始终包含最新版本。(如果有改进)

1
你提供的解决方案是我目前找到的唯一可行的 - 做得好!如果我设法解决这个边缘情况,我一定会通知你。 - Richard Le Mesurier
我正在使用这个解决方案,它非常好用。但是有一个问题,就是 snackbar 和 FAB 出现在应用栏的某个位置上。你有什么办法可以解决吗?顺便说一下,感谢你提供的解决方案。 - Vineet Ashtekar
首先感谢您提供的实用类!我建议不仅要检查API级别是否大于19,还要检查活动窗口是否处于全屏模式。 在我们的应用程序中,您可以切换全屏模式,因此在KeyboardUtil中检查全屏标志会更加方便。 - rekt0x
1
它对我有效!然而,我不知道为什么“getContent”对我无效,但我用以下代码替换它: ((ViewGroup) this.findViewById(android.R.id.content)).getChildAt(0) - cuble
@mikepenz 我已经尝试了这个解决方案,但它只适用于一些设备。它适用于OnePlus 3(7.1.1)和Blu X2(5.1),但不适用于LG Lucid 2(4.1.2)或Galaxy S3 4.4.4。您有什么建议,我应该为旧设备尝试什么呢?谢谢 - alexgophermix
显示剩余10条评论

2

看起来问题出在FrameLayout上,因为它的行为方式是每个子元素都会占据该框架的可见空间,因此不需要调整大小以适应子元素。 尝试使用RelativeLayout。这样应该可以解决问题。


1
用RelativeLayout代替FrameLayout后出现了完全相同的问题。从编辑中可以看出,LinearLayout也没有帮助。 - Graeme
尝试在ScrollView中添加android:fillViewport="true"。 - acm0x
+1 frameLayout 对于 android:windowSoftInputMode="adjustResize" 不太友好,将视图移出 frameLayout 可以解决此问题。然而,这只在 4.0.4 上无法正常工作。 - Dori

1

在没有使用ScrollView作为父视图的情况下,我只是将android:fitsSystemWindows="true"添加到我的父视图(即RelativeLayout),并在活动清单中为该活动添加了adjustResize,这样就可以了。


0
尝试将你的LinearLayout放在ScrollView上,这个方法曾经对我有效。

2
即使将ScrollView用作父级,单击对话框内的EditText也不会调整屏幕的任何部分大小。 - Graeme

0

我不得不设置

<item name="android:windowFullscreen">false</item> 

尽管如此,我从未将其设置为true,应用程序实际上也不是全屏。


-1

正如原帖作者发现的那样,当将Fullscreen标志分配给一个活动时,android:windowFullscreen属性将不起作用,因此当软键盘可见时,窗口不会调整大小,也无法滚动。

简单地移除Fullscreen标志并不使用Fullscreen主题将允许在软键盘可见时滚动。


-1
我不知道为什么,但如果你的主题中有<item name="android:windowTranslucentNavigation">true</item>,请将其更改为false。然后它就会开始工作了。真的很奇怪。

@兄弟,你让我今天过得很愉快。我已经在过去的两天里一直在苦苦思索并努力解决这个问题,但一直没有成功。它像魔法一样奏效了,谢谢! - Prashant Kumar Sharma

-3

请确保在您的样式中将windowTranslucentStatus设置为false


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接