From 90d6a1936dba86fb181d7a61fe28c894561248fd Mon Sep 17 00:00:00 2001 From: d4vidi Date: Wed, 13 Aug 2025 19:12:04 +0300 Subject: [PATCH 1/4] fix(kbd): Allow for kbd-awareness / further inset compute --- e2e/Keyboard.test.js | 14 ++++- .../bottomtabs/BottomTabsController.java | 8 ++- playground/src/screens/KeyboardScreen.tsx | 62 ++++++++++++++----- playground/src/testIDs.ts | 1 + 4 files changed, 62 insertions(+), 23 deletions(-) diff --git a/e2e/Keyboard.test.js b/e2e/Keyboard.test.js index 94b2ea08e3d..1dbb32b8139 100644 --- a/e2e/Keyboard.test.js +++ b/e2e/Keyboard.test.js @@ -1,9 +1,10 @@ import { default as TestIDs, default as testIDs } from '../playground/src/testIDs'; -import Android from './AndroidUtils'; import Utils from './Utils'; const { elementByLabel, elementById } = Utils; +const KBD_OBSCURED_TEXT = 'Keyboard Demo'; + describe.e2e('Keyboard', () => { beforeEach(async () => { await device.launchApp({ newInstance: true }); @@ -11,8 +12,9 @@ describe.e2e('Keyboard', () => { }); it('Push - should close keyboard when Back clicked', async () => { + await expect(elementByLabel(KBD_OBSCURED_TEXT)).toBeVisible(); await elementById(TestIDs.TEXT_INPUT1).tap(); - await expect(elementByLabel('Keyboard Demo')).not.toBeVisible(); + await expect(elementByLabel(KBD_OBSCURED_TEXT)).not.toBeVisible(); await elementById(TestIDs.BACK_BUTTON).tap(); await expect(elementById(testIDs.MAIN_BOTTOM_TABS)).toBeVisible(); }); @@ -20,7 +22,7 @@ describe.e2e('Keyboard', () => { it('Modal - should close keyboard when close clicked', async () => { await elementById(TestIDs.MODAL_BTN).tap(); await elementById(TestIDs.TEXT_INPUT1).tap(); - await expect(elementByLabel('Keyboard Demo')).not.toBeVisible(); + await expect(elementByLabel(KBD_OBSCURED_TEXT)).not.toBeVisible(); await elementById(TestIDs.DISMISS_MODAL_TOPBAR_BTN).tap(); await expect(elementById(testIDs.MAIN_BOTTOM_TABS)).toBeVisible(); }); @@ -46,4 +48,10 @@ describe.e2e('Keyboard', () => { await elementById(TestIDs.MODAL_BTN).tap(); await expect(elementById(TestIDs.TEXT_INPUT1)).not.toBeFocused(); }); + + it(':android should respect UI with keyboard awareness', async () => { + await elementById(TestIDs.PUSH_KEYBOARD_SCREEN_STICKY_FOOTER).tap(); + await elementById(TestIDs.TEXT_INPUT2).tap(); + await expect(elementByLabel(KBD_OBSCURED_TEXT)).toBeVisible(); + }); }); diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java index 78be5f656c2..b3deb2cd87f 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java +++ b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java @@ -316,10 +316,12 @@ public Animator getPopAnimation(Options appearingOptions, Options disappearingOp @Override protected WindowInsetsCompat onApplyWindowInsets(View view, WindowInsetsCompat insets) { Insets sysInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars()); - view.setPaddingRelative(0, 0, 0, sysInsets.bottom); - return WindowInsetsCompat.CONSUMED; - } + Insets imeInsets = insets.getInsets(WindowInsetsCompat.Type.ime()); + int bottomInset = (imeInsets.bottom > 0) ? 0 : sysInsets.bottom; + view.setPaddingRelative(0, 0, 0, bottomInset); + return insets; + } @RestrictTo(RestrictTo.Scope.TESTS) public BottomTabs getBottomTabs() { diff --git a/playground/src/screens/KeyboardScreen.tsx b/playground/src/screens/KeyboardScreen.tsx index d439e72ef43..a199efaacf9 100644 --- a/playground/src/screens/KeyboardScreen.tsx +++ b/playground/src/screens/KeyboardScreen.tsx @@ -1,5 +1,15 @@ import React from 'react'; -import { View, ScrollView, Dimensions, StyleSheet, Image, TextInput, Text } from 'react-native'; +import { + SafeAreaView, + View, + ScrollView, + Dimensions, + StyleSheet, + Image, + TextInput, + Text, + KeyboardAvoidingView, +} from 'react-native'; import { NavigationProps, NavigationComponent, @@ -15,6 +25,7 @@ const KEYBOARD_LABEL = 'Keyboard Demo'; interface Props extends NavigationProps { title?: string; autoFocus?: boolean; + stickyFooter?: boolean; } export default class KeyboardScreen extends NavigationComponent { @@ -34,6 +45,7 @@ export default class KeyboardScreen extends NavigationComponent { }, }; } + constructor(props: Props) { super(props); Navigation.events().bindComponent(this); @@ -50,30 +62,41 @@ export default class KeyboardScreen extends NavigationComponent { } render() { + const FooterRoot = this.props.stickyFooter === true ? KeyboardAvoidingView : View; return ( - +