kirillzyusko / react-native-keyboard-controller

Keyboard manager which works in identical way on both iOS and Android
https://kirillzyusko.github.io/react-native-keyboard-controller/
MIT License
1.79k stars 81 forks source link

IOS: KeyboardToolbar does not respect safe area in landscape orientation #572

Open nullatnothing opened 3 months ago

nullatnothing commented 3 months ago

Describe the bug On IOS devices in landscape orientation the "up arrow" button on the left and the "Close" button on the right are outside the safe area and covered by the "isle" (front camera on iPhone 15).

Code snippet The error occurs in the file: src/components/KeyboardToolbar/index.tsx at line: 216

Here the code:

const styles = StyleSheet.create({
  flex: {
    flex: 1,
  },
 toolbar: {
    position: "absolute",
    bottom: 0,
    alignItems: "center",
    width: "100%",
    flexDirection: "row",
    height: KEYBOARD_TOOLBAR_HEIGHT,
    paddingHorizontal: 8, **<-- HERE THE BUG**
  },

The paddingHorizontal is declared as constant with a value of 8. On IOS it's required to be dynamic to adapt to safe area padding.

Repo for reproducing Create a component with following code:

import React from 'react';
import {View, SafeAreaView} from 'react-native';
import {
KeyboardAwareScrollView,
KeyboardToolbar,
} from 'react-native-keyboard-controller';

const FailingScreen = props => {

return (
    <>
      <SafeAreaView
        <KeyboardAwareScrollView>
            <Text>{'INPUT'}</Text>
            <TextInput />
        </KeyboardAwareScrollView>
      </MODSafeAreaView>
      <KeyboardToolbar doneText={'EXIT'} />
    </>
  );
};

export default FailingScreen;

To Reproduce Steps to reproduce the behavior:

  1. Create app with above component
  2. Run app on IOS device/simulator (eg. iPhone 15)
  3. Tap on TextInput to open the keyboard
  4. Rotate device/simulator
  5. See error

Expected behavior The "up arrow" button on the left and the "Close" button on the right to be within the safe area and not covered by the "isle" (front camera on iPhone 15).

Smartphone (please complete the following information):

Additional context I patched the file: src/components/KeyboardToolbar/index.tsx

with following code:

import { Platform, StyleSheet, Text, View } from "react-native";
import {useSafeAreaInsets} from 'react-native-safe-area-context';
....
const insets = useSafeAreaInsets();
....
const toolbarStyle = useMemo(
    () => [
      styles.toolbar,
      {
        paddingLeft: Platform.OS === 'ios' ? insets.left + 8 : 8,
        paddingRight: Platform.OS === 'ios' ? insets.right  + 8 : 8,
        backgroundColor: `${theme[colorScheme].background}${opacity}`,
      },
    ],
    [colorScheme, opacity, theme, insets],
  );
....
kirillzyusko commented 3 months ago

@nullatnothing are you referring to this bug, right?

image

nullatnothing commented 3 months ago

Yes

kirillzyusko commented 3 months ago

@nullatnothing maybe you know ways how to fix that without using react-native-safe-area-context? 😅

The reason why I'm asking is because I don't want to depend on another library and want to have as less as possible external dependencies. I've tried to use SafeAreaView from react-native but it doesn't give a satisfactory results 😔

nullatnothing commented 2 months ago

@kirillzyusko I've tried all other available modules / views etc. but the only one, that works, is useSafeAreaInsets() from react-native-safe-area-context.

An approach could be following:

Here an example:

extension UIApplication { static var insets: UIEdgeInsets { let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene return scene?.windows.first?.safeAreaInsets ?? .zero } }

Here the docs for native safe area insets.

Here is the approach used by RNSafeAreaContext

I've found, that you already have a reference to UIApplication.shared.keyWindow in the file UIApplication.swift at line 13.

The implementation could be:

static var insets: UIEdgeInsets { return UIApplication.shared.keyWindow?.safeAreaInsets ?? .zero }