2

Update for 2023

The bug is back. I reported it here.

I tested all known fixes and they do not work currently.

Follow these simple steps to reproduce:

  • npx expo init <yourReproNameHere>
  • `Use the "tabs" template
  • Fill any of the two screens with anything (I used <Button/>)
  • Add a <TextInput> at the end of the screen
  • --> The keyboard hides the <TextInput> and <KeyboardAvoidingView> will not fix it

This old image still shows the bug Issue on iOS

[Old Bug which is solved]

Rajendran Nadar
  • 4,962
  • 3
  • 30
  • 51
tomwaitforitmy
  • 509
  • 3
  • 16

2 Answers2

3

I create a wrapping component like this and pass the offset from the screen so that it gets the current context.

import React from 'react'

import { ViewStyle } from 'react-native'

import { KeyboardAvoidingView, Platform, ScrollView } from 'react-native'

type Props = {
    children: any
    keyboardVerticalOffset?: number
    contentContainerStyle?: ViewStyle
}

export default function KeyboardWrapper({
    children,
    keyboardVerticalOffset,
    ...rest
}: Props): JSX.Element {
    return (
        <KeyboardAvoidingView
            style={{ flex: 1 }}
            keyboardVerticalOffset={keyboardVerticalOffset}
            {...(Platform.OS === 'ios' ? { behavior: 'padding' } : {})}>
            <ScrollView
                bounces={false}
                showsVerticalScrollIndicator={false}
                {...rest}>
                {children}
            </ScrollView>
        </KeyboardAvoidingView>
    )
}

Usage in the screen

If you have any sticky elements like topbar or bottom bar you need to add the height so that the keyboard adds the offset correctly.

import { useHeaderHeight } from '@react-navigation/elements'

const height = useHeaderHeight()

<KeyboardWrapper
    keyboardVerticalOffset={height}
    contentContainerStyle={{ flex: 1 }}>
    // ... your elements
</KeyboardWrapper>

This is a working demo https://snack.expo.dev/@raajnadar/fix-keyboardavoidingview-not-working

Rajendran Nadar
  • 4,962
  • 3
  • 30
  • 51
  • ``If you have any sticky elements like topbar or bottom bar you need to add the height so that the keyboard adds the offset correctly.`` That's what I thought, but how do I get those heights? Did you see my simple Snack? Could you fix that case?https://snack.expo.dev/@tomwaitforitmy/keyboardavoidingview – tomwaitforitmy Jun 13 '22 at 11:49
  • I tried passing headerHeight from the navigation screen to the component in my Snack. Nothing changes. I think I would need something like `useMaterialBottomTabsHeight` which does not exist. – tomwaitforitmy Jun 13 '22 at 11:53
  • Please try this minimal example https://snack.expo.dev/@raajnadar/fix-keyboardavoidingview-not-working – Rajendran Nadar Jun 13 '22 at 12:01
  • Not working for me on IOS. Edit field is behind the keyboard. I cannot upload the screenshot here, but I am sure your Snack looks the same if you run it on IOS. – tomwaitforitmy Jun 13 '22 at 12:59
  • See screen shot here: https://imgur.com/a/WwC789A – tomwaitforitmy Jun 13 '22 at 13:05
  • If I am not wrong you want the input to be sticky at the bottom right even without a keyboard correct? – Rajendran Nadar Jun 13 '22 at 13:21
  • I want the edit field to not be behind the keyboard. It should move up, if the keyboard opens -> KeyboardAvoidingView. – tomwaitforitmy Jun 13 '22 at 14:07
  • Can you please check the snack now, it should work now? https://snack.expo.dev/@raajnadar/fix-keyboardavoidingview-not-working – Rajendran Nadar Jul 07 '22 at 20:04
  • No, not even on iOS simulator of expo snacks https://imgur.com/a/7ykPFY1 – tomwaitforitmy Jul 08 '22 at 07:01
  • And my answer https://stackoverflow.com/a/54456543/5519872 – Rajendran Nadar Jul 08 '22 at 08:36
  • You removed the whole content of the screen. That's not my issue anymore. Furthermore, the edit field is sticky on the top. I want the edit field be at the button of the scroll bar content. In reality, I have many edit fields in my scroll bar and almost all of them are hidden by the Keyboard (only the very top fields like yours). Not helpful for me I fear. – tomwaitforitmy Jul 08 '22 at 12:18
  • It seems the issue is due to the Flat list, I have an application in which I have a similar screen with many inputs, an app bar and a bottom bar, I am using the above wrapper and it works very well. – Rajendran Nadar Jul 08 '22 at 12:33
  • I tried to exchange FlatList with ScrollView. In fact, I am only using FlatList, because someone else suggested the issue is due to ScrollView. While the issue is related to anything "scrollable", it is not due to a specific list. Does your app use the Native-StackNavigator AND the Material-Bottom-Tabs both together? If yes, would it be possible for me to see your code base? – tomwaitforitmy Jul 08 '22 at 13:39
  • The issue lies with material bottom tabs, when I switched to bottom tabs it was solved, check the snack that I gave – Rajendran Nadar Jul 08 '22 at 13:42
  • 1
    That is true and works now. So confirmed you need material-bottoms-tabs. – tomwaitforitmy Jul 08 '22 at 14:03
  • 1
    The material bottom tab is from react-native-paper, I will report that to the team – Rajendran Nadar Jul 08 '22 at 14:20
2

There is no need to add 64 to the headerHeight. Here is how I would solve this problem.

const flatListRef = createRef()
const [data, setData] = useState()
const headerHeight = useHeaderHeight();

<View style={{ flex: 1 }}>
        <KeyboardAvoidingView
          behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
          keyboardVerticalOffset={headerHeight}
          style={{ flex: 1 }}>
          <FlatList
            data={data}
            ref={flatListRef}
            onContentSizeChange={() =>
              flatListRef.current.scrollToEnd({ animated: true })
            }
            onLayout={() => flatListRef.current.scrollToEnd({ animated: true })}
            keyExtractor={(item) => item.id}
            renderItem={({ item }) => (
              <Text style={{ flex: 1, paddingVertical: 20 }}>{item.id}</Text>
            )}
          />
          <View style={{ flex: 1, marginBottom: 40 }}>
            <TextInput
              style={{
                backgroundColor: '#2E2E2E',
                width: '100%',
                borderRadius: 18,
                height: 36,
                paddingLeft: 10,
                paddingRight: 10,
                color: '#FFFFFF',
              }}
            />
          </View>
        </KeyboardAvoidingView>
      </View>

Here is a quick and dirty snack which contains an header from a StackNavigator.

David Scholz
  • 8,421
  • 12
  • 19
  • 34
  • The main difference I see is that you use FlatList instead of ScrollView. Is that the cause of the bug or what exactly of your solution solves it? – tomwaitforitmy Mar 14 '22 at 11:53
  • The container of `TextInput` has a `flex: 1` property which pushes it to the bottom. I have removed the additional `64` offset, which is not necessary. – David Scholz Mar 14 '22 at 11:57
  • Your code example works stand alone. I could not make in my app so far however. That means there is something wrong still on my side. Just adding `flex: 1` and removing the 64 did not do the trick ... – tomwaitforitmy Mar 14 '22 at 17:51
  • Share your updated code please, then I could have a look. – David Scholz Mar 15 '22 at 02:17
  • Wow, that would be awesome: https://github.com/tomwaitforitmy/mangi-bevi/tree/DavidScholz and here is how it looks on my devices: https://photos.app.goo.gl/krydfhx6m3bDjvS18 - is the material bottom navigator the cause? – tomwaitforitmy Mar 15 '22 at 18:35
  • I found out that it is indeed material bottom tabs causing the issue. – tomwaitforitmy Mar 20 '22 at 17:10
  • I created a minimal snack if you are in the mood: https://snack.expo.dev/@tomwaitforitmy/keyboardavoidingview – tomwaitforitmy May 15 '22 at 10:22
  • Is this problem related to [this issue on github](https://github.com/react-navigation/react-navigation/issues/10151)? It seems like a general problem with bottom tabs. – David Scholz May 17 '22 at 13:14
  • Hard to answer for me. I will ask there. – tomwaitforitmy May 17 '22 at 14:16