我们为什么要用fitsSystemWindows?

本文详细解释了Android中fitsSystemWindows属性的作用,包括如何避免UI元素与状态栏或导航栏重叠,以及如何自定义此属性的行为。此外还介绍了在不同Android版本中此属性的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文链接:https://github.com/bboyfeiyu/android-tech-frontier/blob/master/issue-35/%E4%B8%BA%E4%BB%80%E4%B9%88%E6%88%91%E4%BB%AC%E8%A6%81%E7%94%A8fitsSystemWindows.md


System windows 指的就是屏幕上status bar、 navigation bar等系统控件所占据的部分。

绝大多数情况下,你都不需要理会status bar或者navigation bar 下面的空间,不过你需要注意不能让你的交互控件(比如Button)藏在status bar 或者 navigation bar下面。而android:fitsSystemWindows="true"的默认行为正好解决了这种情况,这个属性的作用就是通过设置View的padding,使得应用的content部分——Activity中setContentView()中传入的就是content——不会与system window重叠。

还有一些事情需要注意:

  • fitsSystemWindows 需要被设置给根View——这个属性可以被设置给任意View,但是只有根View(content部分的根)外面才是SystemWindow,所以只有设置给根View才有用。
  • Insets始终相对于全屏幕——Insets即边框,它决定着整个Window的边界。对Insets设置padding的时候,这个padding始终是相对于全屏幕的。因为Insets的生成在View layout之前就已经完成了,所以系统对于View长什么样一无所知。
  • 其它padding将通通被覆盖。需要注意,如果你对一个View设置了android:fitsSystemWindows="true",那么你对该View设置的其他padding将通通无效。

在绝大多数情况下,默认情况就已经够用了。比如一个全屏的视屏播放器。如果你不想被ActionBar 或者其他System View遮住的话,那么在MatchParent的ViewGroup上设置fitsSystemWindows="true"即可。

或者,也许你希望你的RecyclerView能够在透明的navigation bar 下面滚动。那么只需将android:fitsSystemWindows="true"android:clipToPadding="false"同时使用即可, 滚动的内容会绘制在navigation bar下面,同时当滚动到最下面的时候,最后一个item下面依旧会有padding,使其可以滚到navigation bar上方(而不是在navigation bar下面滚不上来!)。

译者注:clipToPaddingViewGroup的属性。这个属性定义了是否允许ViewGroup在padding中绘制,该值默认为true,即不允许。

自定义 fitsSystemWindows

但是默认毕竟只是默认。 在KITKAT及以下的版本,你的自定义View能够通过覆盖fitsSystemWindows() : boolean函数,来增加自定义行为。如果返回true,意味着你已经占据了整个Insets,如果返回false,意味着给其他的View依旧留有机会。

而在Lollipop以及更高的版本,我们提供了一些新的API,使得自定义这个行为更加的方便。与之前的版本不同,现在你只需要覆盖OnApplyWindowInsets()方法,该方法允许View消耗它想消耗的任意空间(Insets),同时也能够为子方法,调用dispatchApplyWindowInsets()

更妙的是,利用新的API,你甚至不需要拓展View类,你可以使用ViewCompat.setOnApplyWindowInsetsListener(),这个方法优先于View.onApplyWindowInsets()调用。ViewCompat 同时也提供了 onApplyWindowInsets() 和dispatchApplyWindowInsets()的兼容版本,无需冗长的版本判断。

自定义fitsSystemWindows例子

绝大多数基本的layouts(FrameLayout)都是使用默认的行为,然而依然有一部分layouts已经使用了自定义fitsSystemWindow来实现自定义的功能。

navigation drawer就是一个例子,它需要充满整个屏幕,绘制在透明的status bar下面。

enter image description here

如上图所示,DrawerLayout使用了fitsSystemwindows,他需要让它的子View依旧保持默认行为,即不被actionbar或其他system window遮住,同时依照Material Design的定义,又需要在透明的statusbar下面进行绘制(默认是你在theme中设置的colorPrimaryDark颜色)

你会注意到,在Lollipop及以上版本,DrawerLayout为每一个子View调用了dispatchApplyWindowInsets(),使每一个子View都收到fitsSystemWindows。这与默认行为完全不同,默认行为会使得根View消耗所有的insets,同时子View们永远不会收到fitsSystemWindows

CoordinatorLayout也利用了这一特性,使得其子View有机会截断并对fitsSystemWindows做出自己的反应。同时,它也利用fitsSystemWindows这一flag看其是否需要在statusbar的下方绘制。

同样的,CollapsingToolbarLayoutfitsSystemWindows什么时候把变小的View放在什么地方。

如果你对这些Design Library里的东西感兴趣,请查看Cheesesquare Sample

积极使用系统,而不是老想着Hack

有一件事需要始终牢记,这个属性毕竟不是fitsStatusBar或者fitsNavigationBar。不管是尺寸还是位置,在不同版本间,系统控件都有很大的差距。

但是尽管放心,无论在什么平台上,fitsSystemWindows都会影响Insets,使你的content和system ui不会重叠——除非你自定义这一行为。

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <!-- 语言选择器 --> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:orientation="horizontal"> <Spinner android:id="@+id/language_spinner1" android:layout_width="0dp" android:layout_height="50dp" android:layout_marginRight="10dp" android:layout_weight="1" /> <Spinner android:id="@+id/language_spinner2" android:layout_width="0dp" android:layout_height="50dp" android:layout_marginLeft="10dp" android:layout_weight="1" /> </LinearLayout> <!-- 消息列表(占满中间空间) --> <ListView android:id="@+id/messageListView" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:divider="@android:color/transparent" android:dividerHeight="8dp" android:padding="16dp" /> <!-- 用ScrollView包裹输入区域,确保键盘弹出时可滚动 --> <ScrollView android:layout_width="match_parent" android:layout_height="wrap_content" android:fillViewport="true"> <!-- 关键:确保ScrollView占满可用空间 --> <!-- 输入区域 --> <LinearLayout android:id="@+id/line1" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#F5F5F5" android:orientation="horizontal" android:padding="8dp"> <!-- 语音/键盘切换按钮 --> <ImageButton android:id="@+id/voiceTextToggleButton" android:layout_width="35dp" android:layout_height="35dp" android:layout_gravity="center_vertical" android:background="@mipmap/icon_shengbo" android:padding="8dp" /> <!-- 文字输入框 --> <EditText android:id="@+id/textInputEditText" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:layout_marginRight="4dp" android:layout_weight="1" android:background="@android:color/white" android:ems="10" android:gravity="top" android:hint="输入消息..." android:minHeight="35dp" android:padding="12dp" /> <!-- 语音输入按钮(默认隐藏) --> <Button android:id="@+id/recordButton" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:layout_marginRight="4dp" android:layout_weight="1" android:text="按住 说话" android:textColor="#FFFFFF" android:visibility="gone" android:textSize="16sp" /> </LinearLayout> </ScrollView> </LinearLayout>当键盘弹起时输入框与键盘之间有很大空隙如何解决
最新发布
07-22
<think>我们正在解决软键盘弹出时布局与键盘之间出现多余空白的问题。根据之前的讨论,我们已经尝试了通过监听布局变化来调整内容高度的方法,但是出现了空隙。现在需要调整这个空隙。 可能的原因: 1. 计算可用高度时,没有考虑到状态栏和导航栏的高度。 2. 在调整布局高度时,没有正确减去键盘的高度,导致布局高度设置过大,从而在键盘上方留出了空白。 解决方案: 我们可以改进计算可用高度的方法,确保准确获取键盘的高度,并将布局的高度设置为屏幕高度减去键盘高度(如果有的话)。 步骤: 1. 获取屏幕的完整高度(包括状态栏和导航栏)。 2. 获取内容区域的可见高度(即屏幕高度减去键盘高度,如果有键盘的话)。 3. 计算键盘高度:屏幕高度 - 可见高度。 4. 调整布局:当键盘弹出时,将内容布局的高度设置为可见高度;当键盘收起时,恢复为屏幕高度。 但是,注意在沉浸式模式下,我们可能需要考虑系统栏的高度。 修改后的代码: 在`computeUsableHeight`方法中,我们获取的是内容区域的可见高度(从状态栏底部到键盘顶部,或者到屏幕底部)。 然而,我们之前设置布局高度为`usableHeightSansKeyboard - heightDifference`,这实际上就是`usableHeightNow`。但这样设置后,布局高度就是可见区域的高度,所以应该不会有多余空白。为什么会有空隙呢? 可能的原因是我们没有考虑到导航栏(NavigationBar)的位置。在计算可用高度时,`getWindowVisibleDisplayFrame`返回的矩形区域已经排除了状态栏和导航栏(如果存在的话)。所以,我们计算出的`usableHeightNow`就是内容区域的高度。 但是,当我们设置布局高度为`usableHeightSansKeyboard - heightDifference`(即`usableHeightNow`)时,这个高度并不包括状态栏和导航栏的高度,所以实际上布局被压缩了,而键盘弹出后,整个窗口的可见区域就是除去键盘和系统栏的部分,所以布局应该紧贴键盘顶部。 出现空隙的可能原因: 1. 布局的背景色与键盘背景色不同,导致键盘上方的区域(实际上是导航栏背景)显示为空白(通常是黑色或白色)。 2. 在全面屏设备上,键盘弹出后,底部导航栏会隐藏,但我们的计算没有考虑到这一点。 针对第一种情况,我们可以尝试将布局的背景色设置为与键盘相同的颜色,这样空隙就不明显了。但这不是根本的解决方法。 第二种思路:我们可能没有正确计算出键盘的高度,因为键盘高度可能包括了导航栏的高度。 改进方法: 我们可以这样计算键盘高度: 1. 获取屏幕高度:`mChildOfContent.getRootView().getHeight()` 2. 获取可见区域高度:`rect.bottom - rect.top` 3. 获取状态栏高度:`rect.top` 4. 获取导航栏高度:可以通过`屏幕高度 - (rect.bottom + 状态栏高度)`来计算(在键盘未弹出时),但在键盘弹出时,导航栏可能被隐藏,所以此时导航栏高度为0。 但是,在键盘弹出时,我们关心的是键盘高度,而键盘高度应该是:`屏幕高度 - 可见区域高度 - 状态栏高度`?不,可见区域高度已经包括了状态栏以下到键盘上方的区域。 实际上,`getWindowVisibleDisplayFrame`返回的矩形: - `rect.top`: 状态栏高度 - `rect.bottom`: 屏幕高度 - 导航栏高度(如果导航栏在底部且可见) - 键盘高度(如果键盘弹出) 所以,当键盘弹出时,`rect.bottom`会变小,变小的部分就是键盘高度(如果导航栏被键盘覆盖,那么键盘高度就是屏幕高度减去`rect.bottom`,再减去状态栏高度?不一定,因为`rect.bottom`是从状态栏底部到键盘顶部)。 因此,键盘高度 = 屏幕高度 - `rect.bottom` - 导航栏高度(如果键盘弹出时导航栏仍然存在)? 但是,在全面屏手势的设备上,导航栏是隐藏的,所以键盘高度就是`屏幕高度 - rect.bottom`。 然而,不同设备的行为可能不同,这导致计算复杂。 另一种更可靠的方法是:直接计算键盘高度为`屏幕高度 - rect.bottom`,然后判断这个高度是否超过一定阈值(如屏幕高度的15%),如果是,则认为键盘弹出,然后将布局高度设置为`屏幕高度 - 键盘高度`(即`rect.bottom`),注意这个高度包括了状态栏以下的内容区域。 但是,这样设置后,布局高度就是`rect.bottom`,而`rect.bottom`是从屏幕顶部(状态栏底部)到键盘顶部的位置。所以,我们的内容区域就会在这个范围内。 然而,如果我们的布局原本是延伸到导航栏下面的(通过设置`android:fitsSystemWindows="false"`),那么键盘弹出前,布局是全屏的(包括状态栏和导航栏区域),键盘弹出后,我们设置布局高度为`rect.bottom`,这样布局就会避开状态栏和键盘,但是状态栏部分会变成空白(因为状态栏是系统绘制的,我们的布局内容不会覆盖状态栏,除非设置了全屏)。 因此,我们需要考虑全屏模式下的处理。如果我们的Activity是全屏的(隐藏状态栏和导航栏),那么`rect.top`为0,`rect.bottom`就是可见区域的高度(屏幕高度减去键盘高度)。这样设置布局高度为`rect.bottom`,布局就会紧贴键盘顶部。 但是,如果我们的Activity不是全屏,那么`rect.top`是状态栏高度,我们设置布局高度为`rect.bottom - rect.top`?不对,因为`rect.bottom`已经是从状态栏底部开始计算了,所以可见区域高度就是`rect.bottom - rect.top`,但是我们的布局高度应该设置为整个内容区域的高度,即从状态栏底部到键盘顶部。 实际上,我们之前设置的是`mChildOfContent.getLayoutParams().height = usableHeightSansKeyboard - heightDifference;`,其中`usableHeightSansKeyboard`是屏幕高度(包括状态栏和导航栏),`heightDifference`是键盘高度(包括导航栏?),所以这样减出来的高度可能不对。 我们尝试这样修改: 在键盘弹出时,将内容布局的高度设置为`rect.bottom`(即从屏幕顶部到键盘顶部,注意`rect`的坐标系是相对于整个窗口的,所以`rect.bottom`就是屏幕顶部到键盘顶部的距离)。但是,这样设置的话,状态栏会覆盖在我们的内容上面?因为状态栏是透明的,所以内容会从状态栏下面开始,这样状态栏会覆盖内容。 所以,我们需要在计算时考虑状态栏的高度,将内容布局向下移动状态栏的高度?但是这样会破坏全屏效果。 更好的做法是:让Activity全屏,然后通过设置`android:fitsSystemWindows="true"`来让系统自动处理系统栏的留白。但是这样就需要改变Activity的样式。 考虑到问题的复杂性,我们可以尝试另一种思路:使用`adjustResize`模式,并确保我们的布局能够正确调整。但是,在沉浸式模式下,`adjustResize`会失效,所以我们需要手动调整。 我们回到最初的问题:键盘和布局之间有空隙。这个空隙可能是导航栏的高度。因为键盘弹出后,导航栏可能仍然存在(在非全面屏设备上),它位于键盘上方,所以我们的布局应该位于导航栏上方,键盘上方。 因此,我们需要在计算可用高度时,排除导航栏的高度(如果存在)。但是,当键盘弹出时,导航栏可能被键盘覆盖(在全面屏设备上,导航栏是隐藏的),所以情况复杂。 一个相对简单且有效的方案是:使用`adjustNothing`模式,然后自己完全控制键盘弹出时的布局变化。我们可以通过监听键盘高度变化,将需要上移的输入框向上移动键盘的高度,这样就不会有多余的空白。 但是,我们这里已经有一个调整整个布局高度的方案,所以我们可以继续优化这个方案。 修改后的计算可用高度方法: ```java private void possiblyResizeChildOfContent() { Rect rect = new Rect(); mChildOfContent.getWindowVisibleDisplayFrame(rect); int usableHeightNow = rect.bottom - rect.top; int screenHeight = mChildOfContent.getRootView().getHeight(); int keyboardHeight = screenHeight - rect.bottom; // 如果键盘高度大于0,且与之前的高度不同 if (keyboardHeight > screenHeight / 4) { // 键盘弹出 // 设置内容高度为:屏幕高度 - 键盘高度 - 状态栏高度(rect.top)? // 注意:rect.top是状态栏高度,我们想要的内容区域高度应该是从状态栏底部到键盘顶部,即usableHeightNow // 但是usableHeightNow已经去除了状态栏,所以直接设置高度为usableHeightNow mChildOfContent.getLayoutParams().height = usableHeightNow; } else { // 键盘收起,恢复全屏 mChildOfContent.getLayoutParams().height = screenHeight; } mChildOfContent.requestLayout(); } ``` 但是,这里有一个问题:在键盘未弹出时,`usableHeightNow`是屏幕高度减去状态栏和导航栏的高度(如果导航栏可见)。所以,当键盘收起时,我们设置高度为`screenHeight`(整个屏幕高度),这样就会覆盖系统栏,所以我们需要在布局中设置`fitsSystemWindows`为true,或者自己处理系统栏的插入。 因此,我们可能需要根据是否全屏来采取不同的处理。 考虑到时间,这里提供一个更通用的方法:我们只调整布局的paddingBottom,而不是直接改变高度。这样,当键盘弹出时,我们增加底部padding,使得内容不被键盘遮挡,同时也不会出现布局高度变化导致的空白。 具体步骤: 1. 计算键盘高度:`keyboardHeight = screenHeight - rect.bottom` 2. 当键盘弹出时(`keyboardHeight`大于一定阈值),设置内容布局的`paddingBottom`为键盘高度。 3. 当键盘收起时,设置`paddingBottom`为0。 这样,内容就会自动上移,而底部留出键盘高度的padding,这个padding的颜色由布局背景决定,我们可以设置成和键盘一样的颜色,这样看起来就没有空隙了。 修改后的代码: ```java private void possiblyResizeChildOfContent() { Rect rect = new Rect(); mChildOfContent.getWindowVisibleDisplayFrame(rect); int screenHeight = mChildOfContent.getRootView().getHeight(); int keyboardHeight = screenHeight - rect.bottom; // 键盘高度阈值,比如屏幕高度的15% int threshold = screenHeight / 6; if (keyboardHeight > threshold) { // 键盘弹出 mChildOfContent.setPadding(0, 0, 0, keyboardHeight); } else { // 键盘收起 mChildOfContent.setPadding(0, 0, 0, 0); } } ``` 注意:这种方法可能会影响布局,因为改变了padding,所以布局内的内容需要能够适应padding。 但是,这种方法简单,且避免了直接修改高度带来的问题。另外,我们可以通过设置相同的背景色来消除空隙的视觉差异。 另外,我们还需要考虑导航栏的情况。在有些设备上,键盘弹出时,导航栏是覆盖在键盘上的(比如一些平板设备),这时`rect.bottom`会包含导航栏的高度,所以计算出来的键盘高度会偏大。因此,我们需要判断导航栏的位置。 不过,对于大多数手机,特别是全面屏手机,键盘弹出时,导航栏是隐藏的,所以`rect.bottom`就是键盘的顶部位置。 因此,我们可以尝试这种方法。 修改后的辅助类: ```java public class KeyboardHeightHelper { private View mChildOfContent; private int previousKeyboardHeight = -1; public KeyboardHeightHelper(Activity activity) { FrameLayout content = activity.findViewById(android.R.id.content); mChildOfContent = content.getChildAt(0); mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(this::adjustLayout); } private void adjustLayout() { Rect rect = new Rect(); mChildOfContent.getWindowVisibleDisplayFrame(rect); int screenHeight = mChildOfContent.getRootView().getHeight(); int keyboardHeight = screenHeight - rect.bottom; // 如果键盘高度变化超过100像素,或者状态改变(出现/消失),则调整 if (Math.abs(keyboardHeight - previousKeyboardHeight) > 100 || (keyboardHeight > 0 && previousKeyboardHeight == 0) || (keyboardHeight == 0 && previousKeyboardHeight > 0)) { // 设置底部padding mChildOfContent.setPadding(0, 0, 0, keyboardHeight); mChildOfContent.requestLayout(); previousKeyboardHeight = keyboardHeight; } } } ``` 在Activity中使用: ```java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new KeyboardHeightHelper(this); } ``` 注意:这个辅助类只调整了内容View的底部padding,这样当键盘弹出时,内容View的底部就会留出键盘高度的空白,从而避免被键盘遮挡。同时,由于padding区域的颜色和布局背景一致,所以如果键盘背景和布局背景不同,可能会看到色差。我们可以通过设置键盘上方的布局背景色与键盘背景色一致来消除这种差异。 另外,我们还可以考虑使用`android:windowBackground`设置窗口背景色,使其与键盘背景色相同。 如果以上方法还不能满足需求,可以考虑使用第三方库,比如`androidx.core:core`中的`WindowInsetsCompat`来获取精确的键盘高度,并处理系统栏的插入。 在Android 11及以上,推荐使用`WindowInsets` API来获取键盘高度,这样更准确。 示例(使用WindowInsetsCompat): ```java ViewCompat.setOnApplyWindowInsetsListener(mChildOfContent, (v, insets) -> { int imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom; int systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom; // 如果IME高度大于0,说明键盘弹出 if (imeHeight > 0) { v.setPadding(0, 0, 0, imeHeight - systemBars); // 注意:这里可能需要减去系统栏,因为IME高度可能包括系统栏 } else { v.setPadding(0, 0, 0, 0); } return insets; }); ``` 但是,这种方法需要API 20以上,并且需要设置Activity的`windowSoftInputMode`为`adjustResize`。 鉴于我们的Activity已经设置了`SOFT_INPUT_ADJUST_RESIZE`,所以可以使用`WindowInsets`。 因此,我们可以根据API版本选择不同的实现。 总结:推荐使用`WindowInsetsCompat`来获取键盘高度,因为它更准确,并且能处理不同系统版本和厂商的差异。 步骤: 1. 添加依赖:`implementation 'androidx.core:core:1.6.0'` 2. 在Activity的onCreate中设置: ```java ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.content), (v, insets) -> { int imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom; int systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom; // 如果键盘弹出,则设置底部padding为键盘高度减去系统栏高度(因为键盘可能覆盖了系统栏,所以不需要重复留出系统栏区域) // 但是注意:键盘弹出时,系统栏可能被键盘覆盖,所以systemBars可能为0(在全面屏手势设备上) v.setPadding(v.getPaddingLeft(), v.getPaddingTop(), v.getPaddingRight(), imeHeight > 0 ? imeHeight - systemBars : 0); return insets; }); ``` 注意:`content`是Activity的content view(即FrameLayout,id为android.R.id.content)的子View(也就是我们的布局根视图)。 但是,这种方法在键盘弹出时,系统会自动调整布局,我们只是进一步调整padding,确保内容不被遮挡。 然而,我们之前已经设置了`SOFT_INPUT_ADJUST_RESIZE`,系统已经调整了布局,为什么还会出现空隙?可能是因为系统调整后,布局底部与键盘顶部之间还有系统导航栏的高度。所以,我们通过设置padding来消除这个高度。 因此,这种方法可以更精确地控制。 考虑到兼容性,我们结合两种方法: 如果API>=20,使用WindowInsetsCompat;否则,使用全局布局监听。 由于时间关系,这里只提供WindowInsetsCompat的方案,因为它是官方推荐且更准确。 最终方案: 1. 在AndroidManifest.xml中设置Activity的`windowSoftInputMode`为`adjustResize`。 2. 在Activity的onCreate中,设置WindowInsets监听。 示例代码: ```java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); View rootView = findViewById(android.R.id.content).getChildAt(0); ViewCompat.setOnApplyWindowInsetsListener(rootView, (v, windowInsets) -> { WindowInsetsCompat insets = WindowInsetsCompat.toWindowInsetsCompat(windowInsets); int imeBottom = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom; int systemBarsBottom = insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom; // 计算需要设置的bottom padding int bottomPadding = 0; if (imeBottom > 0) { // 键盘弹出,减去系统栏高度(如果系统栏在键盘上方,则systemBarsBottom为0;如果系统栏在键盘下方,则systemBarsBottom不为0,但键盘会覆盖系统栏,所以应该不需要额外处理) // 实际上,键盘弹出时,系统栏通常会被键盘覆盖,所以systemBarsBottom可能是0 // 我们直接使用imeBottom作为paddingBottom,因为系统已经将布局调整到键盘上方,但可能键盘和布局之间还有系统栏的高度,所以这里我们直接设置paddingBottom为0,让系统处理,但发现有空隙,所以需要加上键盘高度? // 实际上,系统已经为布局留出了键盘高度,所以不需要额外设置。但是为什么会有空隙?这个空隙就是系统栏的高度。 // 因此,我们设置bottomPadding = imeBottom - systemBarsBottom; bottomPadding = imeBottom - systemBarsBottom; } v.setPadding(v.getPaddingLeft(), v.getPaddingTop(), v.getPaddingRight(), bottomPadding); return windowInsets; }); } ``` 注意:这个方案可能还需要调整,因为`imeBottom`已经包含了系统栏的高度?需要测试。 由于问题的复杂性,可能需要针对不同设备进行测试和调整。如果时间有限,建议使用成熟的第三方库,如`com.github.yshrsmz:keyboardvisibilityevent`等。 最后,如果以上方法都不能解决问题,还可以考虑使用`adjustPan`模式,它不会调整布局大小,而是将输入框滚动到可见区域。但是,如果输入框在底部,它可能会将整个界面向
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值