Skip to content

Commit

Permalink
Include existing height when calculating new one for KeyboardAvoiding…
Browse files Browse the repository at this point in the history
…View (#34749)

Summary:
Currently, height is sometimes the only valid option for pushing `TextInput` up in the layout on Android. The problem is when switching keyboards. For instance, switching from ABC to emojis. This will trigger keyboard show events and recalculate the height for the `KeyboardAvoidingView`. Since the keyboard is still showing, the view has the height that was previously calculated and thus `frame` represents that. This means the `frame.height` has adjustments for the keyboard calculated in it, but it is used the same way as if the keyboard was not showing. This results in wrong calculation and the input showing at the incorrect place in the layout (mostly hidden under the keyboard)

This fix simply uses the previous calculation to offset `frame.height`, resulting in the correct height and smooth switching between keyboards. It's also scoped only to height mode since that's where the problem shows.

_Note: I mention android here, but it fixes it for both platforms. It's just that iOS usually works best with different behaviour so it's rarely used there._

## Changelog

[General] [Added] - Include `this.state.bottom` when calculating new keyboard height to fix android keyboard switching

Pull Request resolved: #34749

Test Plan:
With simple code:

```jsx
import { StatusBar } from "expo-status-bar";
import React from "react";
import {
  KeyboardAvoidingView,
  StyleSheet,
  Text,
  TextInput,
  View,
} from "react-native";

export default function App() {
  return (
    <KeyboardAvoidingView style={styles.container} behavior="height">
      <Text>Open up App.js to start working on your app!</Text>
      <StatusBar style="auto" />
      <TextInput style={{ backgroundColor: "red", width: "100%" }} />
    </KeyboardAvoidingView>
  );
}

const styles = StyleSheet.create({
  container: {
    padding: 32,
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "space-between",
  },
});
```

Notice the consistency of the TextInput after the changes, while before it would just move around more you switch the keyboards.

|  Before  | After  |
|---|---|
| ![2022-09-21 13-59-09 2022-09-21 14_01_44](https://user-images.githubusercontent.com/3984319/191499509-b41280a0-2969-4fe6-8796-c5695b999f27.gif)  | ![2022-09-21 14-03-33 2022-09-21 14_04_30](https://user-images.githubusercontent.com/3984319/191499628-a5832b88-e511-448d-8081-ac48d3a3690a.gif)  |

Reviewed By: cipolleschi

Differential Revision: D39718812

Pulled By: NickGerleman

fbshipit-source-id: 2550182e846f3f8e719d727fa8e6d87165faebf6
  • Loading branch information
pfulop authored and facebook-github-bot committed Sep 26, 2022
1 parent 70d86e7 commit f85e2ec
Showing 1 changed file with 7 additions and 0 deletions.
7 changes: 7 additions & 0 deletions Libraries/Components/Keyboard/KeyboardAvoidingView.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
const keyboardY =
keyboardFrame.screenY - (this.props.keyboardVerticalOffset ?? 0);

if (this.props.behavior === 'height') {
return Math.max(
this.state.bottom + frame.y + frame.height - keyboardY,
0,
);
}

// Calculate the displacement needed for the view such that it
// no longer overlaps with the keyboard
return Math.max(frame.y + frame.height - keyboardY, 0);
Expand Down

0 comments on commit f85e2ec

Please sign in to comment.