【问题标题】:Android How to adjust layout in Full Screen Mode when softkeyboard is visibleAndroid如何在软键盘可见时在全屏模式下调整布局
【发布时间】:2011-11-17 01:02:15
【问题描述】:

我已经研究了很多以在软键盘处于活动状态时调整布局并且我已经成功实现了它,但是当我在清单文件的活动标记中使用 android:theme="@android:style/Theme.NoTitleBar.Fullscreen" 时出现问题。

为此,我使用了 android:windowSoftInputMode="adjustPan|adjustResize|stateHidden" 和不同的选项,但没有运气。

在那之后,我以编程方式实现了FullScreen,并尝试了各种布局来使用FullScreen,但都是徒劳的。

我参考了这些链接,并在此处查看了许多与此问题相关的帖子:

http://android-developers.blogspot.com/2009/04/updating-applications-for-on-screen.html

http://davidwparker.com/2011/08/30/android-how-to-float-a-row-above-keyboard/

这里是xml代码:

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

    <ScrollView android:id="@+id/parentScrollView"
        android:layout_width="fill_parent" android:layout_height="wrap_content">

        <LinearLayout android:layout_width="fill_parent"
            android:layout_height="fill_parent" android:orientation="vertical">

            <TextView android:id="@+id/setup_txt" android:layout_width="wrap_content"
                android:layout_height="wrap_content" android:text="Setup - Step 1 of 3"
                android:textColor="@color/top_header_txt_color" android:textSize="20dp"
                android:padding="8dp" android:gravity="center_horizontal" />

            <TextView android:id="@+id/txt_header" android:layout_width="fill_parent"
                android:layout_height="40dp" android:text="AutoReply:"
                android:textColor="@color/top_header_txt_color" android:textSize="14dp"
                android:textStyle="bold" android:padding="10dp"
                android:layout_below="@+id/setup_txt" />

            <EditText android:id="@+id/edit_message"
                android:layout_width="fill_parent" android:layout_height="wrap_content"
                android:text="Some text here." android:textSize="16dp"
                android:textColor="@color/setting_editmsg_color" android:padding="10dp"
                android:minLines="5" android:maxLines="6" android:layout_below="@+id/txt_header"
                android:gravity="top" android:scrollbars="vertical"
                android:maxLength="132" />

            <ImageView android:id="@+id/image_bottom"
                android:layout_width="fill_parent" android:layout_height="wrap_content"
                android:layout_below="@+id/edit_message" />

        </LinearLayout>
    </ScrollView>

    <RelativeLayout android:id="@+id/scoringContainerView"
        android:layout_width="fill_parent" android:layout_height="50px"
        android:orientation="vertical" android:layout_alignParentBottom="true"
        android:background="#535254">

        <Button android:id="@+id/btn_save" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:layout_alignParentRight="true"
            android:layout_marginTop="7dp" android:layout_marginRight="15dp"
            android:layout_below="@+id/edit_message"
            android:text = "Save" />

        <Button android:id="@+id/btn_cancel" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:layout_marginTop="7dp"
            android:layout_marginRight="10dp" android:layout_below="@+id/edit_message"
            android:layout_toLeftOf="@+id/btn_save" android:text = "Cancel" />

    </RelativeLayout>
</RelativeLayout>

我希望当软键盘出现时,底部的 2 个按钮应该向上。

【问题讨论】:

  • 我认为您必须在 ScrollView 和 EditText 下方添加按钮。
  • 我已经尝试了很多不起作用的选项...
  • 将你的按钮放在一个框架布局中并将框架布局的权重设置为1,最后只使用android:windowSoftInputMode="adjustPan"告诉我这是否可行..
  • @VineetShukla 你有没有找到全屏的工作??
  • 注意不要同时使用adjustResizeadjustPan,来自android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE的javadoc:“这不能与{@link SOFT_INPUT_ADJUST_PAN}结合使用”跨度>

标签: android android-layout android-widget android-softkeyboard


【解决方案1】:

基于 yghm 的解决方法,我编写了一个方便类,它允许我用单线解决问题(当然是在将新类添加到我的源代码之后)。单线是:

     AndroidBug5497Workaround.assistActivity(this);

而实现类是:


public class AndroidBug5497Workaround {

    // For more information, see https://issuetracker.google.com/issues/36911528
    // 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 - r.top);
    }
}

希望这对某人有所帮助。

【讨论】:

  • 谢谢!我不知道为什么,但我必须将return (r.bottom - r.top); 替换为return r.bottom 才能在我的HTC One Mini 上运行,否则状态栏的大小会将活动视图推得太高。不过,我还没有在另一台设备上测试过它。希望能有所帮助。
  • 您好 Joseph johnson,我使用了您的代码,它运行良好。但是现在在一些小型设备上面临一个问题,它显示键盘和布局之间的间隙(空白屏幕)。你对这个问题有什么想法吗?我也试过返回 r.bottom。
  • 约瑟夫约翰逊:我已经实现了你的方法,当我们点击顶部的编辑文本时它工作正常,但是当我们点击底部的编辑文本时,所有的设计都会上升
  • 不幸的是,它不适用于 Nexus 7 (2013)。即使设置了adjustNothing,它仍然可以平移。
  • 很棒的答案,非常感谢。它在 Nexus 6 上运行,但我必须使用 frameLayoutParams.height = usableHeightNow; 而不是使用 frameLayoutParams.height = usableHeightSansKeyboard; 如果我不这样做,一些元素会落在屏幕之外。
【解决方案2】:

由于已经选择了答案并且已知问题是一个错误,我想我会添加一个“可能的解决方法”。

当显示软键盘时,您可以切换全屏模式。这允许“adjustPan”正常工作。

换句话说,我仍然使用 @android:style/Theme.Black.NoTitleBar.Fullscreen 作为应用程序主题的一部分和 stateVisible |adjustResize 作为活动窗口软输入模式的一部分,但为了让它们一起工作,我必须在键盘出现之前切换全屏模式。

使用以下代码:

关闭全屏模式

getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

开启全屏模式

getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);

注意 - 灵感来自:Hiding Title in a Fullscreen mode

【讨论】:

  • 感谢您花时间解决这个问题,为此 +1。我一定会测试这种方法,如果它对我有用,我会尽快通知您,谢谢。
  • 工作正常!真的很好的解决方案!从我这边 +1。
  • 键盘卡扣,使键盘背景变黑。捕捉效果看起来不太好:(
  • 哇,谢谢...通过结合 AndroidBug5497Workaround 提到的解决方法,它对我非常有效...我将合并的源上传到 GitHub...github.com/CrandellWS/AndroidBug5497Workaround/blob/master/…
【解决方案3】:

我尝试了solution from Joseph Johnson,但和其他人一样,我遇到了内容和键盘之间的差距问题。出现此问题是因为在使用全屏模式时,软输入模式始终是 pan。当您激活将被软输入隐藏的输入字段时,此平移会干扰 Joseph 的解决方案。

当软输入出现时,内容首先根据其原始高度平移,然后根据约瑟夫的解决方案要求的布局调整大小。调整大小和随后的布局不会撤消平移,这会导致间隙。事件的完整顺序是:

  1. 全局布局监听器
  2. 平移
  3. 内容布局(= 内容的实际大小调整)

无法禁用平移,但可以通过更改内容的高度来强制平移偏移为 0。这可以在侦听器中完成,因为它在平移发生之前运行。将内容高度设置为可用高度可以获得流畅的用户体验,即没有闪烁。

我也做了这些改变。如果其中任何一个引入问题,请告诉我:

  • 切换确定可用高度以使用getWindowVisibleDisplayFrameRect 被缓存以防止出现一点不需要的垃圾。
  • 也允许移除监听器。当您为具有不同全屏要求的不同片段重用 Activity 时,这很有用。
  • 不区分键盘显示或隐藏,但始终将内容高度设置为可见显示框高度。

它已经在 Nexus 5 和运行 API 级别 16-24 的模拟器上进行了测试,屏幕尺寸从小到大不等。

代码已移植到 Kotlin,但将我的更改移植回 Java 很简单。如果您需要帮助,请告诉我:

class AndroidBug5497Workaround constructor(activity: Activity) {
    private val contentContainer = activity.findViewById(android.R.id.content) as ViewGroup
    private val rootView = contentContainer.getChildAt(0)
    private val rootViewLayout = rootView.layoutParams as FrameLayout.LayoutParams
    private val viewTreeObserver = rootView.viewTreeObserver
    private val listener = ViewTreeObserver.OnGlobalLayoutListener { possiblyResizeChildOfContent() }

    private val contentAreaOfWindowBounds = Rect()
    private var usableHeightPrevious = 0

    // I call this in "onResume()" of my fragment
    fun addListener() {
        viewTreeObserver.addOnGlobalLayoutListener(listener)
    }

    // I call this in "onPause()" of my fragment
    fun removeListener() {
        viewTreeObserver.removeOnGlobalLayoutListener(listener)
    }

    private fun possiblyResizeChildOfContent() {
        contentContainer.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds)
        val usableHeightNow = contentAreaOfWindowBounds.height()
        if (usableHeightNow != usableHeightPrevious) {
            rootViewLayout.height = usableHeightNow
            // Change the bounds of the root view to prevent gap between keyboard and content, and top of content positioned above top screen edge.
            rootView.layout(contentAreaOfWindowBounds.left, contentAreaOfWindowBounds.top, contentAreaOfWindowBounds.right, contentAreaOfWindowBounds.bottom)
            rootView.requestLayout()

            usableHeightPrevious = usableHeightNow
        }
    }
}

【讨论】:

  • 这似乎是最好的答案。我在这里移植到 java gist.github.com/grennis/2e3cd5f7a9238c59861015ce0a7c5584 。请注意,我收到了观察者不存在的异常,并且还必须进行检查。
  • 天哪!一直在遍历所有系统视图层次结构以寻找那个 Ghost 空间。我差点放弃电脑去买一辆食品卡车,但在最后一分钟看到了你的答案。它有效:)
  • @Greg Ennis 感谢 Java 移植。节省了大量的精力和时间。
  • @GregEnnis,谢谢,您的解决方案适用于 onResume()、onPause()、onDestroy()(请参阅 GitHub 代码中的 cmets)。
  • 这对我有用,只是 removeListener 调用似乎不起作用。我在possiblyResizeChildOfContent 调用和removeListener 调用中都设置了断点,即使在我点击removeListener 断点之后,possiblyResizeChildOfContent 仍然被调用。其他人有这个问题吗?
【解决方案4】:

如果您使用系统 UI 方法 (https://developer.android.com/training/system-ui/immersive.html),我刚刚找到了一个简单可靠的解决方案。

它适用于您使用View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 的情况,例如如果您使用的是CoordinatorLayout

它不适用于WindowManager.LayoutParams.FLAG_FULLSCREEN(你也可以用android:windowFullscreen在主题中设置),但你可以用SYSTEM_UI_FLAG_LAYOUT_STABLE达到类似的效果(“具有相同的视觉效果”according to the docs)这个解决方案应该会再次起作用。

getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION /* If you want to hide navigation */
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE)

我已经在运行 Marshmallow 的设备上对其进行了测试。

关键是软键盘也是系统窗口之一(如状态栏和导航栏),所以系统调度的WindowInsets包含了准确可靠的信息。

对于DrawerLayout 等我们试图在状态栏后面绘制的用例,我们可以创建一个仅忽略顶部插图的布局,并应用占软键盘的底部插图。

这是我的自定义FrameLayout

/**
 * Implements an effect similar to {@code android:fitsSystemWindows="true"} on Lollipop or higher,
 * except ignoring the top system window inset. {@code android:fitsSystemWindows="true"} does not
 * and should not be set on this layout.
 */
public class FitsSystemWindowsExceptTopFrameLayout extends FrameLayout {

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

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

    public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs,
                                                 int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs,
                                                 int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            setPadding(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(),
                    insets.getSystemWindowInsetBottom());
            return insets.replaceSystemWindowInsets(0, insets.getSystemWindowInsetTop(), 0, 0);
        } else {
            return super.onApplyWindowInsets(insets);
        }
    }
}

并使用它:

<com.example.yourapplication.FitsSystemWindowsExceptTopFrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- Your original layout here -->
</com.example.yourapplication.FitsSystemWindowsExceptTopFrameLayout>

理论上,这应该适用于任何未经疯狂修改的设备,比任何试图将随机的屏幕尺寸 1/31/4 作为参考的黑客要好得多。

(它需要 API 16+,但我只在 Lollipop+ 上使用全屏来在状态栏后面绘图,所以在这种情况下这是最好的解决方案。)

【讨论】:

  • @Dilip 它适用于 API 16+,前提是满足上述条件。
【解决方案5】:

请注意,当为活动设置WindowManager.LayoutParams.FLAG_FULLSCREEN 时,android:windowSoftInputMode="adjustResize" 不起作用。 您有两个选择。

  1. 为您的活动禁用全屏模式。 Activity 在全屏模式下不会重新调整大小。您可以在 xml(通过更改活动的主题)或 Java 代码中执行此操作。在 onCreate() 方法中添加以下行。

    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);   
    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);`
    

  1. 使用另一种方式来实现全屏模式。在 onCreate() 方法中添加以下代码。

    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
    getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
    View decorView = getWindow().getDecorView();
    // Hide the status bar.
    int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
    decorView.setSystemUiVisibility(uiOptions);`
    

请注意,method-2 仅适用于 Android 4.1 及更高版本。

【讨论】:

  • @AnshulTyagi method-2 仅适用于 Android 4.1 及更高版本。
  • 分别在 5.0 和 4.4.2、Nexus 9 和 Samsung s4 上测试,第二种方法不起作用。
  • 第二种方法根本行不通,我浪费了很多时间。
  • 谢谢你,拯救我的一天。
【解决方案6】:

我也不得不面对这个问题,我在 HTC one、galaxy s1、s2、s3、note 和 HTC sense 上进行了检查。

在布局的根视图上放置一个全局布局监听器

mRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener(){
            public void onGlobalLayout() {
                checkHeightDifference();
            }
    });

在那里我检查了高度差,如果屏幕的高度差大于屏幕高度的三分之一,那么我们可以假设键盘是打开的。 取自this answer

private void checkHeightDifference(){
    // get screen frame rectangle 
    Rect r = new Rect();
    mRootView.getWindowVisibleDisplayFrame(r);
    // get screen height
    int screenHeight = mRootView.getRootView().getHeight();
    // calculate the height difference
    int heightDifference = screenHeight - (r.bottom - r.top);

    // if height difference is different then the last height difference and
    // is bigger then a third of the screen we can assume the keyboard is open
    if (heightDifference > screenHeight/3 && heightDifference != mLastHeightDifferece) {
        // keyboard visiblevisible
        // get root view layout params
        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mRootView.getLayoutParams();
        // set the root view height to screen height minus the height difference
        lp.height = screenHeight - heightDifference;
        // call request layout so the changes will take affect
        .requestLayout();
        // save the height difference so we will run this code only when a change occurs.
        mLastHeightDifferece = heightDifference;
    } else if (heightDifference != mLastHeightDifferece) {
        // keyboard hidden
        PFLog.d("[ChatroomActivity] checkHeightDifference keyboard hidden");
        // get root view layout params and reset all the changes we have made when the keyboard opened.
        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mRootView.getLayoutParams();
        lp.height = screenHeight;
        // call request layout so the changes will take affect
        mRootView.requestLayout();
        // save the height difference so we will run this code only when a change occurs.
        mLastHeightDifferece = heightDifference;
    }
}

这可能不是防弹的,也许在某些设备上它不起作用,但它对我有用,希望它也能帮助你。

【讨论】:

  • 需要一些调整,但它奏效了。在 Nexus 7 2013 中,我不得不将键盘高度 (screenHeight/3) 降低一些像素。好主意,谢谢!
【解决方案7】:

android:fitsSystemWindows="true" 添加到布局中,此布局将调整大小。

【讨论】:

  • 这就是为我解决的问题。此外,请确保将其设置在正确的视图上。如果您的背景应该位于状态栏下方,请不要将其设置在那里,而应设置在里面的布局上。可能 EditText 视图等应该在里面的第二个布局内。还请观看此演讲,因为它使事情更清楚:youtube.com/watch?v=_mGDMVRO3iE
  • 也为我工作。感谢@Stan 评论,我还能够使其与 FULLSCREEN 主题一起使用,将该属性放在 ViewPager 而不是活动/片段布局上。
  • 非常适合我。我把它放在我的片段布局的顶部,现在全屏主题与adjustResize 标志配合得很好。不靠谱。
【解决方案8】:

我实施了 Joseph Johnson 解决方案并且效果很好,我注意到使用此解决方案后,有时应用程序上的抽屉无法正常关闭。 当用户关闭edittexts所在的片段时,我添加了一个删除监听器removeOnGlobalLayoutListener的功能。

    //when the application uses full screen theme and the keyboard is shown the content not scrollable! 
//with this util it will be scrollable once again
//http://stackoverflow.com/questions/7417123/android-how-to-adjust-layout-in-full-screen-mode-when-softkeyboard-is-visible
public class AndroidBug5497Workaround {


    private static AndroidBug5497Workaround mInstance = null;
    private View mChildOfContent;
    private int usableHeightPrevious;
    private FrameLayout.LayoutParams frameLayoutParams;
    private ViewTreeObserver.OnGlobalLayoutListener _globalListener;

    // 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 AndroidBug5497Workaround getInstance (Activity activity) {
        if(mInstance==null)
        {
            synchronized (AndroidBug5497Workaround.class)
            {
                mInstance = new AndroidBug5497Workaround(activity);
            }
        }
        return mInstance;
    }

    private AndroidBug5497Workaround(Activity activity) {
        FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
        mChildOfContent = content.getChildAt(0);
        frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();

        _globalListener = new ViewTreeObserver.OnGlobalLayoutListener()
        {

            @Override
            public void onGlobalLayout()
            {
                 possiblyResizeChildOfContent();
            }
        };
    }

    public void setListener()
    {
         mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(_globalListener);
    }

    public void removeListener()
    {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            mChildOfContent.getViewTreeObserver().removeOnGlobalLayoutListener(_globalListener);
        } else {
            mChildOfContent.getViewTreeObserver().removeGlobalOnLayoutListener(_globalListener);
        }
    }

    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 - r.top);
    } 
}

使用我的编辑文本所在的类

@Override
public void onStart()
{
    super.onStart();
    AndroidBug5497Workaround.getInstance(getActivity()).setListener();
}

@Override
public void onStop()
{
    super.onStop();
    AndroidBug5497Workaround.getInstance(getActivity()).removeListener();
}

【讨论】:

    【解决方案9】:

    我目前正在使用这种方法,它就像一个魅力。诀窍是我们从上面和下面的 21 的不同方法中获取 keyboard height,然后在我们的活动中将其用作根视图的底部填充。我认为您的布局不需要顶部填充(位于状态栏下方),但如果您这样做,请通知我更新我的答案。

    MainActivity.java

    public class MainActivity extends AppCompatActivity {
        @Override
        protected void onCreate(final Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            RelativeLayout mainLayout = findViewById(R.id.main_layout);
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                ViewCompat.setOnApplyWindowInsetsListener(mainLayout , new OnApplyWindowInsetsListener() {
                    @Override
                    public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) {
                        v.setPadding(0, 0, 0, insets.getSystemWindowInsetBottom());
                        return insets;
                    }
                });
            } else {
                View decorView = getWindow().getDecorView();
                final View contentView = mainLayout;
                decorView.getViewTreeObserver().addOnGlobalLayoutListener(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);
                            }
                        }
                    }
                });
            }
        }
    ...
    }
    

    不要忘记使用 id 来处理您的根视图:

    activity_main.xml

    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/main_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    

    希望对某人有所帮助。

    【讨论】:

    • 无法理解,为什么这个答案仍然不在顶部。其他人的故障,闪光,但这个很棒,特别是如果你有 5+ api。
    • 我已经尝试了很多解决方案,除了这个之外没有一个可以工作。谢谢Sdghasemi。
    【解决方案10】:

    要让它与全屏一起使用:

    使用离子键盘插件。这使您可以聆听键盘何时出现和消失。

    OnDeviceReady 添加这些事件监听器:

    // Allow Screen to Move Up when Keyboard is Present
    window.addEventListener('native.keyboardshow', onKeyboardShow);
    // Reset Screen after Keyboard hides
    window.addEventListener('native.keyboardhide', onKeyboardHide);
    

    逻辑:

    function onKeyboardShow(e) {
        // Get Focused Element
        var thisElement = $(':focus');
        // Get input size
        var i = thisElement.height();
        // Get Window Height
        var h = $(window).height()
        // Get Keyboard Height
        var kH = e.keyboardHeight
        // Get Focused Element Top Offset
        var eH = thisElement.offset().top;
        // Top of Input should still be visible (30 = Fixed Header)
        var vS = h - kH;
        i = i > vS ? (vS - 30) : i;
        // Get Difference
        var diff = (vS - eH - i);
        if (diff < 0) {
            var parent = $('.myOuter-xs.myOuter-md');
            // Add Padding
            var marginTop = parseInt(parent.css('marginTop')) + diff - 25;
            parent.css('marginTop', marginTop + 'px');
        }
    }
    
    function onKeyboardHide(e) {
      // Remove All Style Attributes from Parent Div
      $('.myOuter-xs.myOuter-md').removeAttr('style');
    }
    

    基本上,如果它们的差异是负数,那么这就是键盘覆盖您输入的像素数量。所以如果你通过这个调整你的父 div 应该抵消它。

    将超时添加到逻辑中说 300 毫秒也应该优化性能(因为这将允许键盘时间出现。

    【讨论】:

      【解决方案11】:

      我尝试了 Joseph Johnson 的课程,效果很好,但并不能完全满足我的需求。而不是模拟 android:windowSoftInputMode="adjustResize",我需要模拟 android:windowSoftInputMode="adjustPan"。

      我将它用于全屏 web 视图。要将内容视图平移到正确的位置,我需要使用一个 javascript 界面,该界面提供有关具有焦点的页面元素位置的详细信息,因此正在接收键盘输入。我省略了这些细节,但提供了我对约瑟夫约翰逊课程的重写。它将为您实现自定义平移与他的调整大小提供一个非常坚实的基础。

      package some.package.name;
      
      import some.package.name.JavaScriptObject;
      
      import android.app.Activity;
      import android.graphics.Rect;
      import android.view.View;
      import android.view.ViewTreeObserver;
      import android.widget.FrameLayout;
      
      //-------------------------------------------------------
      // ActivityPanner Class
      //
      // Convenience class to handle Activity attributes bug.
      // Use this class instead of windowSoftInputMode="adjustPan".
      //
      // To implement, call enable() and pass a reference
      // to an Activity which already has its content view set.
      // Example:
      //      setContentView( R.layout.someview );
      //      ActivityPanner.enable( this );
      //-------------------------------------------------------
      //
      // Notes:
      //
      // The standard method for handling screen panning
      // when the virtual keyboard appears is to set an activity
      // attribute in the manifest.
      // Example:
      // <activity
      //      ...
      //      android:windowSoftInputMode="adjustPan"
      //      ... >
      // Unfortunately, this is ignored when using the fullscreen attribute:
      //      android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
      //
      //-------------------------------------------------------
      public class ActivityPanner {
      
          private View contentView_;
          private int priorVisibleHeight_;
      
          public static void enable( Activity activity ) {
              new ActivityPanner( activity );
          }
      
          private ActivityPanner( Activity activity ) {
              FrameLayout content = (FrameLayout)
                  activity.findViewById( android.R.id.content );
              contentView_ = content.getChildAt( 0 );
              contentView_.getViewTreeObserver().addOnGlobalLayoutListener(
                  new ViewTreeObserver.OnGlobalLayoutListener() {
                      public void onGlobalLayout() { panAsNeeded(); }
              });
          }
      
          private void panAsNeeded() {
      
              // Get current visible height
              int currentVisibleHeight = visibleHeight();
      
              // Determine if visible height changed
              if( currentVisibleHeight != priorVisibleHeight_ ) {
      
                  // Determine if keyboard visiblity changed
                  int screenHeight =
                      contentView_.getRootView().getHeight();
                  int coveredHeight =
                      screenHeight - currentVisibleHeight;
                  if( coveredHeight > (screenHeight/4) ) {
                      // Keyboard probably just became visible
      
                      // Get the current focus elements top & bottom
                      // using a ratio to convert the values
                      // to the native scale.
                      float ratio = (float) screenHeight / viewPortHeight();
                      int elTop = focusElementTop( ratio );
                      int elBottom = focusElementBottom( ratio );
      
                      // Determine the amount of the focus element covered
                      // by the keyboard
                      int elPixelsCovered = elBottom - currentVisibleHeight;
      
                      // If any amount is covered
                      if( elPixelsCovered > 0 ) {
      
                          // Pan by the amount of coverage
                          int panUpPixels = elPixelsCovered;
      
                          // Prevent panning so much the top of the element
                          // becomes hidden
                          panUpPixels = ( panUpPixels > elTop ?
                                          elTop : panUpPixels );
      
                          // Prevent panning more than the keyboard height
                          // (which produces an empty gap in the screen)
                          panUpPixels = ( panUpPixels > coveredHeight ?
                                          coveredHeight : panUpPixels );
      
                          // Pan up
                          contentView_.setY( -panUpPixels );
                      }
                  }
                  else {
                      // Keyboard probably just became hidden
      
                      // Reset pan
                      contentView_.setY( 0 );
                  }
      
                  // Save usabale height for the next comparison
                  priorVisibleHeight_ = currentVisibleHeight;
              }
          }
      
          private int visibleHeight() {
              Rect r = new Rect();
              contentView_.getWindowVisibleDisplayFrame( r );
              return r.bottom - r.top;
          }
      
          // Customize this as needed...
          private int viewPortHeight() { return JavaScriptObject.viewPortHeight(); }
          private int focusElementTop( final float ratio ) {
              return (int) (ratio * JavaScriptObject.focusElementTop());
          }
          private int focusElementBottom( final float ratio ) {
              return (int) (ratio * JavaScriptObject.focusElementBottom());
          }
      
      }
      

      【讨论】:

      • 似乎是我需要的,你能添加一个完整的样本吗?感谢您的工作!
      • 我不想发布整个项目。我提供的内容将为您带来一个非常有效的解决方案。您需要定义自己:创建一个“JavaScriptObject”类并将其作为 js 接口注入到您的 webview 中(请查看 webview 文档)。如果编写全面使用 webview 的东西,你很有可能已经这样做了。在 web 视图中添加 JavaScript 以侦听焦点事件并将有关焦点元素定位的数据提供给 JavaScriptObject 类。
      【解决方案12】:

      1) 创建KeyboardHeightHelper:

      public class KeyboardHeightHelper {
      
          private final View decorView;
          private int lastKeyboardHeight = -1;
      
          public KeyboardHeightHelper(Activity activity, View activityRootView, OnKeyboardHeightChangeListener listener) {
              this.decorView = activity.getWindow().getDecorView();
              activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
                  int keyboardHeight = getKeyboardHeight();
                  if (lastKeyboardHeight != keyboardHeight) {
                      lastKeyboardHeight = keyboardHeight;
                      listener.onKeyboardHeightChange(keyboardHeight);
                  }
              });
          }
      
          private int getKeyboardHeight() {
              Rect rect = new Rect();
              decorView.getWindowVisibleDisplayFrame(rect);
              return decorView.getHeight() - rect.bottom;
          }
      
          public interface OnKeyboardHeightChangeListener {
              void onKeyboardHeightChange(int keyboardHeight);
          }
      }
      

      2) 让你的活动全屏:

      activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

      3) 监听键盘高度变化并为您的视图添加底部填充:

      View rootView = activity.findViewById(R.id.root); // your root view or any other you want to resize
      KeyboardHeightHelper effectiveHeightHelper = new KeyboardHeightHelper(
              activity, 
              rootView,
              keyboardHeight -> rootView.setPadding(0, 0, 0, keyboardHeight));
      

      所以,每次键盘出现在屏幕上时 - 视图的底部填充都会改变,内容也会重新排列。

      【讨论】:

        【解决方案13】:

        确实,无论我在FullScreen 模式下选择什么windowSoftInputMode,软键盘外观似乎都不会以任何方式影响Activity

        虽然我找不到关于这个属性的太多文档,但我认为FullScreen 模式是为不需要大量使用软键盘的游戏应用程序设计的。如果您的活动需要通过软键盘进行用户交互,请重新考虑使用非全屏主题。您可以使用 NoTitleBar 主题关闭 TitleBar。为什么要隐藏通知栏?

        【讨论】:

          【解决方案14】:

          请保持android:windowSoftInputMode="adjustResize"。因为它只保留"adjustResize""adjustPan" 中的一个(窗口调整模式使用adjustResize 或adjustPan 指定。强烈建议您始终指定其中一个)。你可以在这里找到它: http://developer.android.com/resources/articles/on-screen-inputs.html

          它非常适合我。

          【讨论】:

          • 我没有遇到任何问题...我也尝试过您的 XML。这也适用于..m 使用 Os 2.2 版
          • 我只尝试过全屏模式……我在我的 Nexus One 和 Nexus S 上测试它……它可以工作。
          • 我已经尝试过 Galaxy S、HTC wildfire、HTC Hero、摩托罗拉 Deify 和 Sony XPeria。不适用于任何单一设备。
          【解决方案15】:

          仅在使用 AdjustPan 时使用 android:windowSoftInputMode="adjustResize|stateHidden,然后它会禁用调整大小属性

          【讨论】:

          • 我也用过....请让你在全屏模式下进行,你在哪个设备上测试?
          • HTC NEXUS 一,ok i hvnt 添加全屏
          • 你能用getWindow().requestFeature(Window.FEATURE_NO_TITLE); onCreate() 而不是使用主题?
          • 上面的代码在没有全屏的情况下工作正常,但是从 xml 或代码添加全屏......它不起作用......请仔细阅读问题。
          【解决方案16】:

          我使用 Joseph Johnson 创建了 AndroidBug5497Workaround 类,但在软键盘和视图之间出现了空白。我提到了这个链接Greg Ennis。对上述内容进行一些更改后,这是我的最终工作代码。

           public class SignUpActivity extends Activity {
          
           private RelativeLayout rlRootView; // this is my root layout
           private View rootView;
           private ViewGroup contentContainer;
           private ViewTreeObserver viewTreeObserver;
           private ViewTreeObserver.OnGlobalLayoutListener listener;
           private Rect contentAreaOfWindowBounds = new Rect();
           private FrameLayout.LayoutParams rootViewLayout;
           private int usableHeightPrevious = 0;
          
           private View mDecorView;
          
           @Override
           protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_sign_up);
            mDecorView = getWindow().getDecorView();
            contentContainer =
             (ViewGroup) this.findViewById(android.R.id.content);
          
            listener = new OnGlobalLayoutListener() {
             @Override
             public void onGlobalLayout() {
              possiblyResizeChildOfContent();
             }
            };
          
            rootView = contentContainer.getChildAt(0);
            rootViewLayout = (FrameLayout.LayoutParams)
            rootView.getLayoutParams();
          
            rlRootView = (RelativeLayout) findViewById(R.id.rlRootView);
          
          
            rlRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
             @Override
             public void onGlobalLayout() {
              int heightDiff = rlRootView.getRootView().getHeight() - rlRootView.getHeight();
              if (heightDiff > Util.dpToPx(SignUpActivity.this, 200)) {
               // if more than 200 dp, it's probably a keyboard...
               //  Logger.info("Soft Key Board ", "Key board is open");
          
              } else {
               Logger.info("Soft Key Board ", "Key board is CLOSED");
          
               hideSystemUI();
              }
             }
            });
           }
          
           // This snippet hides the system bars.
           protected void hideSystemUI() {
            // Set the IMMERSIVE flag.
            // Set the content to appear under the system bars so that the 
            content
            // doesn't resize when the system bars hide and show.
            mDecorView.setSystemUiVisibility(
             View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
           }
           @Override
           protected void onPause() {
            super.onPause();
            if (viewTreeObserver.isAlive()) {
             viewTreeObserver.removeOnGlobalLayoutListener(listener);
            }
           }
          
           @Override
           protected void onResume() {
            super.onResume();
            if (viewTreeObserver == null || !viewTreeObserver.isAlive()) {
             viewTreeObserver = rootView.getViewTreeObserver();
            }
            viewTreeObserver.addOnGlobalLayoutListener(listener);
           }
          
           @Override
           protected void onDestroy() {
            super.onDestroy();
            rootView = null;
            contentContainer = null;
            viewTreeObserver = null;
           }
           private void possiblyResizeChildOfContent() {
            contentContainer.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds);
          
            int usableHeightNow = contentAreaOfWindowBounds.height();
          
            if (usableHeightNow != usableHeightPrevious) {
             rootViewLayout.height = usableHeightNow;
             rootView.layout(contentAreaOfWindowBounds.left,
              contentAreaOfWindowBounds.top, contentAreaOfWindowBounds.right, contentAreaOfWindowBounds.bottom);
             rootView.requestLayout();
          
             usableHeightPrevious = usableHeightNow;
            } else {
          
             this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
            }
           }
          }
          

          【讨论】:

            【解决方案17】:

            基于https://stackoverflow.com/a/19494006/1815624 并希望实现它...

            更新的想法


            结合来自

            的答案

            相关代码:

                    if (heightDifference > (usableHeightSansKeyboard / 4)) {
            
                        // keyboard probably just became visible
                        frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
                        activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
                        activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
                    } else {
            
                        // keyboard probably just became hidden
                        if(usableHeightPrevious != 0) {
                            frameLayoutParams.height = usableHeightSansKeyboard;
                            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
                            activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
            
                        }
            

            完整源代码https://github.com/CrandellWS/AndroidBug5497Workaround/blob/master/AndroidBug5497Workaround.java

            老想法

            在打开键盘之前创建容器高度的静态值 键盘打开时根据usableHeightSansKeyboard - heightDifference设置容器高度,关闭时设置回保存的值

            if (heightDifference > (usableHeightSansKeyboard / 4)) {
                            // keyboard probably just became visible
                            frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
                            int mStatusHeight = getStatusBarHeight();
                            frameLayoutParams.topMargin = mStatusHeight;
                            ((MainActivity)activity).setMyMainHeight(usableHeightSansKeyboard - heightDifference);
            
                            if(BuildConfig.DEBUG){
                                Log.v("aBug5497", "keyboard probably just became visible");
                            }
                        } else {
                            // keyboard probably just became hidden
                            if(usableHeightPrevious != 0) {
                                frameLayoutParams.height = usableHeightSansKeyboard;
                                ((MainActivity)activity).setMyMainHeight();    
                            }
                            frameLayoutParams.topMargin = 0;
            
                            if(BuildConfig.DEBUG){
                                Log.v("aBug5497", "keyboard probably just became hidden");
                            }
                        }
            

            MainActivity 中的方法

            public void setMyMainHeight(final int myMainHeight) {
            
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        ConstraintLayout.LayoutParams rLparams =  (ConstraintLayout.LayoutParams) myContainer.getLayoutParams();
                        rLparams.height = myMainHeight;
            
                        myContainer.setLayoutParams(rLparams);
                    }
            
                });
            
            }
            
            int mainHeight = 0;
            public void setMyMainHeight() {
            
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        ConstraintLayout.LayoutParams rLparams =  (ConstraintLayout.LayoutParams) myContainer.getLayoutParams();
                        rLparams.height = mainHeight;
            
                        myContainer.setLayoutParams(rLparams);
                    }
            
                });
            
            }
            

            示例容器 XML

            <android.support.constraint.ConstraintLayout
                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.support.constraint.ConstraintLayout
                        android:id="@+id/my_container"
                        android:layout_width="match_parent"
                        android:layout_height="0dp"
                        app:layout_constraintHeight_percent=".8">
            

            如果需要,可以添加类似的边距...

            另一个考虑因素是使用填充,可以在以下位置找到一个示例:

            https://github.com/mikepenz/MaterialDrawer/issues/95#issuecomment-80519589

            【讨论】:

              【解决方案18】:

              您希望底栏粘在视图的底部,但是当显示键盘时,它们应该向上移动以放置在键盘上方,对吧?

              你可以试试这段代码sn-p:

              <RelativeLayout
                  xmlns:android="http://schemas.android.com/apk/res/android"
                  ...>
              
                  <RelativeLayout
                      android:id="@+id/RelativeLayoutTopBar"
                  ...>
                  </RelativeLayout>
              
                  <LinearLayout
                      android:id="@+id/LinearLayoutBottomBar"
                      android:layout_alignParentBottom = true
                      ...>
                  </LinearLayout>
              
                  <LinearLayout
                  android:layout_width="fill_parent"
                  android:layout_height="390dp"
                  android:orientation="vertical" 
                  android:layout_above="@+id/LinearLayoutBottomBar"
                  android:layout_below="@+id/RelativeLayoutTopBar"> 
              
                  <ScrollView 
                      android:layout_width="fill_parent" 
                      android:layout_height="wrap_content"
                      android:layout_marginTop="10dp"
                      android:layout_marginBottom="10dp"
                      android:id="@+id/ScrollViewBackground">
              
                          ...
              
                      </ScrollView>
                   </LinearLayout>
                </RelativeLayout>
              

              BottomBar 将贴在视图的底部,包含 ScrollView 的 LinearLayout 将在显示顶部/底部栏和键盘后占据视图的左侧。让我知道它是否也适合您。

              【讨论】:

              • 很奇怪,因为它在我的应用程序中工作了好几次。顺便说一句,RelativeLayout 没有方向,因此您可以在代码中删除这些属性。我刚刚意识到我可以将代码 sn-p 减少到以下行: android:layout_below="@+id/scoringContainerView" 您必须将其添加到 ScrollView
              • 全屏?你的意思是顶部没有布局?
              • 不......我的意思是没有显示电池寿命、设备连接等的状态栏......
              • 不,状态栏在我的应用程序中可见。您可以尝试更改布局的顺序,这意味着您将布局代码与其他代码上方的按钮一起放置,然后再试一次?也许你必须先定义它们才能使用 layout_below
              • 请仔细阅读问题......我已经提到我在全屏模式下遇到问题......
              【解决方案19】:

              感谢约瑟夫的回答。但是,在方法 possibleResizeChildOfContent() 中,部分

              else {
                          // keyboard probably just became hidden
                          frameLayoutParams.height = usableHeightSansKeyboard;
                      }
              

              对我不起作用,因为视图的下部被隐藏了。 所以我只好取了一个全局变量restoreHeight,在构造函数中,我插入了最后一行

              restoreHeight = frameLayoutParams.height;
              

              然后我将前面提到的部分替换为

              else {
                          // keyboard probably just became hidden
                          frameLayoutParams.height = restoreHeight;
                      }
              

              但我不知道为什么您的代码不适合我。如果有人能阐明这一点,那将是非常有帮助的。

              【讨论】:

                【解决方案20】:

                我只是使用全屏模式来隐藏状态栏。但是,我希望应用程序在显示键盘时调整大小。所有其他解决方案(可能由于发布时间)对我来说都很复杂或无法使用(希望避免更改 Java 代码以解雇 PhoneGap Build)。

                我没有使用全屏,而是将我的 Android 配置修改为非全屏:

                            <preference name="fullscreen" value="false" />
                

                并通过命令行添加了cordova-plugin-statusbar

                cordova plugin add cordova-plugin-statusbar
                

                当应用加载完毕后,我简单地调用插件上的一个方法来隐藏自己,比如:

                    if (window.cordova && window.cordova.platformId == 'android' && window.StatusBar)
                        window.StatusBar.hide();
                

                这就像一个魅力。唯一真正的缺点是状态栏在应用程序加载时短暂可见。根据我的需要,这不是问题。

                【讨论】:

                  【解决方案21】:

                  我已经从 stackOverflow 中尝试了所有可能的答案,经过一周的 Long search 后我终于解决了。 我使用了坐标布局,并用 linearLayout 改变了它,我的问题得到了解决。我不知道坐标布局可能有错误或任何我的错误。

                  【讨论】:

                    【解决方案22】:

                    我尝试了许多解决方案,包括 Joseph Johnson 和 Johan Stuyts 的。但结果,在所有情况下,我在某些设备(如联想 s820)上的内容和键盘之间都有空白。 因此,我对他们的代码进行了一些更改,最终得到了可行的解决方案。

                    我的想法基于在显示键盘时在内容顶部添加边距。

                    contentContainer.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds);
                        int usableHeightNow = contentAreaOfWindowBounds.height();
                    
                        if (usableHeightNow != usableHeightPrevious) {
                    
                            int difference = usableHeightNow - usableHeightPrevious;
                    
                            if (difference < 0 && difference < -150) {
                                keyboardShowed = true;
                                rootViewLayout.topMargin -= difference + 30;
                                rootViewLayout.bottomMargin += 30;
                            }
                            else if (difference < 0 && difference > -150){
                                rootViewLayout.topMargin -= difference + 30;
                            }
                            else if (difference > 0 && difference > 150) {
                                keyboardShowed = false;
                                rootViewLayout.topMargin = 0;
                                rootViewLayout.bottomMargin = 0;
                            }
                    
                            rootView.requestLayout();
                    
                            Log.e("Bug Workaround", "Difference: " + difference);
                    
                            usableHeightPrevious = usableHeightNow;
                    }
                    

                    如您所见,我在差异上添加了 30 像素,因为屏幕顶部和带有边距的内容区域之间有一个小的空白区域。而且我不知道它是从哪里出现的,所以我决定只缩小边距,现在它完全符合我的需要。

                    【讨论】:

                      【解决方案23】:

                      今天无法在全屏问题上调整调整大小是 android sdk 的实际问题。

                      从我找到的答案:
                      the solution - 但是解决方案在图片问题上显示了这个:

                      比我找到the solution 并删除一项不必要的操作:

                      this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
                      

                      那么,在 Kotlin 上查看我的固定解决方案代码:

                      class AndroidBug5497Workaround constructor(val activity: Activity) {
                      
                          private val content = activity.findViewById<View>(android.R.id.content) as FrameLayout
                      
                          private val mChildOfContent = content.getChildAt(0)
                          private var usableHeightPrevious: Int = 0
                          private val contentContainer = activity.findViewById(android.R.id.content) as ViewGroup
                          private val rootView = contentContainer.getChildAt(0)
                          private val rootViewLayout = rootView.layoutParams as FrameLayout.LayoutParams
                      
                          private val listener = {
                              possiblyResizeChildOfContent()
                          }
                      
                          fun addListener() {
                              mChildOfContent.apply {
                                  viewTreeObserver.addOnGlobalLayoutListener(listener)
                      
                              }
                          }
                      
                          fun removeListener() {
                              mChildOfContent.apply {
                                  viewTreeObserver.removeOnGlobalLayoutListener(listener)
                              }
                          }
                      
                          private fun possiblyResizeChildOfContent() {
                              val contentAreaOfWindowBounds = Rect()
                              mChildOfContent.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds)
                              val usableHeightNow = contentAreaOfWindowBounds.height()
                      
                              if (usableHeightNow != usableHeightPrevious) {
                                  rootViewLayout.height = usableHeightNow
                                  rootView.layout(contentAreaOfWindowBounds.left,
                                          contentAreaOfWindowBounds.top, contentAreaOfWindowBounds.right, contentAreaOfWindowBounds.bottom);
                                  mChildOfContent.requestLayout()
                                  usableHeightPrevious = usableHeightNow
                              }
                          }
                      }
                      

                      我的bug修复工具代码:

                       class LeaveDetailActivity : BaseActivity(){
                      
                          private val keyBoardBugWorkaround by lazy {
                              AndroidBug5497Workaround(this)
                          }
                      
                          override fun onCreate(savedInstanceState: Bundle?) {
                              super.onCreate(savedInstanceState)
                              setContentView(R.layout.activity_main)
                      
                          }
                      
                          override fun onResume() {
                              keyBoardBugWorkaround.addListener()
                              super.onResume()
                          }
                      
                          override fun onPause() {
                              keyBoardBugWorkaround.removeListener()
                              super.onPause()
                          }
                      }
                      

                      【讨论】:

                        【解决方案24】:
                        private void resizeWindowOnKeyboardVisible() {
                                    RelativeLayout rootLayout;
                                    rootLayout = findViewById(R.id.rootLayout);
                                    this.getWindow().getDecorView().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                            
                                        ViewGroup.LayoutParams layoutParams = rootLayout.getLayoutParams();
                                        int height ;
                            
                                        @Override
                                        public void onGlobalLayout() {
                                            Rect r = new Rect();
                                            getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
                                            int screenHeight = rootLayout.getContext().getResources().getDisplayMetrics().heightPixels;
                                            int heightDiff = screenHeight - r.bottom;
                            
                                            if (heightDiff > screenHeight*0.15)
                                            {
                                                height = screenHeight - heightDiff;
                                                layoutParams.height=height;
                                                rootLayout.setLayoutParams(layoutParams);
                                            }else{
                                                height=ViewGroup.LayoutParams.MATCH_PARENT;
                                                if( height!=layoutParams.height) {
                                                    layoutParams.height = height;
                                                    rootLayout.setLayoutParams(layoutParams);
                                                }
                                            }
                                        }
                                    });
                                }
                        

                        使用 android:windowSoftInputMode="adjustResize|stateHidden 可能不适用于所有情况,并且 android:fitsSystemWindows="true 在您使用 SYSTEM_UI_FLAG_FULLSCREEN 标记时也无济于事。要在键盘可见时调整视图/窗口/webview,请执行以下操作。

                        • 使用 RelativeLayout 作为根布局。
                        • 在一个activity中声明上述resizeWindowOnKeyboardVisible()方法并在onCreate()方法中setContentView()之后调用。

                        它也适用于 Android 11 (API 30)。

                        【讨论】:

                          【解决方案25】:

                          还有另一种方法,无需创建自己的帮助类或计算屏幕高度的函数。而是使用ViewCompat.setOnApplyWindowInsetsListener。 使用监听器,您可以检查键盘是否打开并根据键盘高度设置底部填充。

                          // the root view of your webview, e.g FrameLayout or LinearLayout
                              rootView = view.findViewById(R.id.whatever);
                              
                              ViewCompat.setOnApplyWindowInsetsListener(rootView, (webView, insets) -> {
                                  
                                  // checks if keyboard is visible, the Type.ime() stands for Input Method
                                  boolean isKeyboardVisible = insets.isVisible(WindowInsetsCompat.Type.ime());
                                  
                                  // get the keyboard height and use the height as bottom padding for your view
                                  int bottomKeyboardPadding = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom;
                          
                                  
                                  if (isKeyboardVisible) { webView.setPadding(0, 0, 0, bottomKeyboardPadding); }
                                  else { webView.setPadding(0, 0, 0, 0); }
                          
                                  return insets;
                              });
                          

                          【讨论】:

                            【解决方案26】:

                            就我而言,这个问题是在我将 Crosswalk 添加到我的 Cordova 应用程序后开始发生的。我的应用没有在全屏和 android:windowSoftInputMode="adjustPan" 中使用。

                            我已经在应用程序中安装了离子键盘插件,因此可以轻松检测键盘是向上还是向下:

                            // Listen for events to when the keyboard is opened and closed
                            window.addEventListener("native.keyboardshow", keyboardUp, false);
                            window.addEventListener('native.keyboardhide', keyboardDown, false);
                            
                            function keyboardUp()
                            {
                                $('html').addClass('keyboardUp');
                            }
                            
                            function keyboardDown()
                            {
                                $('html').removeClass('keyboardUp');
                            }
                            

                            我尝试了上面的所有修复,但最终为我做的简单的一行是这段 css:

                            &.keyboardUp {
                                    overflow-y: scroll;
                            }
                            

                            希望这可以节省您在这方面花费的几天时间。 :)

                            【讨论】:

                            • 我正在使用带有 cordova 的人行横道以及 android:windowSoftInputMode="adjustPan"。但是,它不起作用。我看到该类被添加到 html 元素中,但 css 对屏幕没有影响。您是否还有其他设置可以让屏幕移动?
                            • 我必须设置 add transform:translateY(0px) 才能工作。但是,滚动根本不起作用。有什么想法吗?
                            【解决方案27】:

                            不要使用:

                            getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
                            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
                            

                            因为效果不好。 取而代之的是:

                            fun setFullScreen(fullScreen: Boolean) {
                                    val decorView = getWindow().getDecorView()
                                    val uiOptions : Int
                                    if(fullScreen){
                                        uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN // this hide statusBar
                                        toolbar.visibility = View.GONE // if you use toolbar
                                        tabs.visibility = View.GONE // if you use tabLayout
                                    } else {
                                        uiOptions = View.SYSTEM_UI_FLAG_VISIBLE // this show statusBar
                                        toolbar.visibility = View.VISIBLE
                                        tabs.visibility = View.VISIBLE
                                    }
                                    decorView.setSystemUiVisibility(uiOptions)
                                }
                            

                            【讨论】:

                              猜你喜欢
                              • 2023-03-19
                              • 1970-01-01
                              • 2011-10-09
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 2016-06-05
                              • 1970-01-01
                              • 1970-01-01
                              相关资源
                              最近更新 更多