react-native-keyboard-controller replaces the guesswork in KeyboardAvoidingView with keyboard height synced to the native animation. On form screens, that means the active TextInput stays visible, the scroll feels like a system sheet, and Android behaves the same as iOS - without per-platform behavior props.
// app/_layout.tsx - provider once at the rootimport { Stack } from "expo-router";import { KeyboardProvider } from "react-native-keyboard-controller";export default function RootLayout() { return ( <KeyboardProvider> <Stack /> </KeyboardProvider> );}
Missing KeyboardProvider - KeyboardAwareScrollView falls back to inconsistent behavior or zero keyboard height. Fix: Wrap the root layout, not individual screens.
bottomOffset left at 0 with a toolbar - The focused field hides under KeyboardToolbar. Fix: Set bottomOffset to toolbar height + safe area (often 44–62 px before inset).
keyboardShouldPersistTaps omitted - Taps on submit buttons dismiss the keyboard without firing onPress. Fix:keyboardShouldPersistTaps="handled" on the scroll view.
Nesting KeyboardAvoidingView inside KeyboardAwareScrollView - Double adjustment overshoots and causes bounce. Fix: Pick one strategy - keyboard-controller OR avoiding view, not both.
FlatList inside KeyboardAwareScrollView - Virtualized lists inside scroll views break measurement and performance. Fix: Put inputs in ListHeaderComponent / ListFooterComponent, or use useKeyboardHandler for chat layouts.
Android tab bar resize - Bottom tabs slide up with the keyboard and squash the form. Fix:softwareKeyboardLayoutMode: "pan" or tabBarHideOnKeyboard: true.
Reanimated not configured - useKeyboardHandler worklets fail silently or throw on Android. Fix: Verify react-native-reanimated babel plugin per Expo Reanimated docs.