tomwaitforitmy
tomwaitforitmy

Reputation: 727

KeyboardAvoidingView not working on iOS with react navigation header and material bottom tabs?

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:

This old image still shows the bug Issue on iOS

[Old Bug which is solved]

Upvotes: 2

Views: 2325

Answers (2)

Rajendran Nadar
Rajendran Nadar

Reputation: 5438

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

Upvotes: 3

David Scholz
David Scholz

Reputation: 9846

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.

Upvotes: 2

Related Questions