Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Native : Subviews of KeyboardAvoidingView have lag / move at different speeds

I would like them all the subviews to move in one clean motion, but if you look at the gif, you can see that the Text subview and the TextInput subview overlap and move at different speeds. It looks like the Text subview adjusts its position instantly where as the button and TextInput subviews adjust their position in more of an Ease in Ease out manner.

enter image description here

Main exported component

class SearchScreen extends React.Component {

    state = {search:""}

    render(){
        getArguments = {
            search: this.state.search
        }
        return (
            <KeyboardAvoidingView behavior="padding" style={styles.container}>
                <Text style={styles.searchTitle}>Search for a Movie in the OMDB Database</Text>
                <TextInput style={styles.searchField} onChangeText={text => this.setState({search:text})} ></TextInput>
                <SearchButton navigation = {this.props.navigation} getArguments={getArguments}/>
            </KeyboardAvoidingView>
        )
    }

}

Styling

const styles = StyleSheet.create({
    container: {
        flex:1,
        backgroundColor: '#C8FEFE',
        alignItems: 'center',
        justifyContent: 'center'
    },
    searchButton: {
      marginTop: 20,
      backgroundColor: '#24D9E8',
      borderRadius: 5,
      padding: 5
    },
    searchField: {
      backgroundColor: '#FFF',
      textAlign: 'center',
      width: 200,
      borderRadius: 5,
      margin: 20,
      height: 30
    },
    searchTitle:{
        fontWeight: 'bold',
        fontSize: 20,
        textAlign:'center'
    }
  });

Github

Full project on github

like image 864
Sam Avatar asked Dec 28 '19 21:12

Sam


2 Answers

Solution 1: Quick fix for iOS

You can wrap your elements in a View, which will make them react to keyboard the way you want:

// styles
contentContainer: {
    alignItems: 'center',
}

// SearchScreen
<View style={styles.contentContainer}>
    <Text style={styles.searchTitle}>Search for a Movie in the OMDB Database</Text>
    <TextInput style={styles.searchField} onChangeText={text => this.setState({search:text})} ></TextInput>
    <SearchButton navigation = {this.props.navigation} getArguments={getArguments}/>
</View>

However, this will only work on iOS. Keyboard works slightly differently on Android. So solution 2 is a more solid way to do things.

Solution 2: Animations

Keyboard avoidance is quite tricky, Spencer Carli's article that Dominik referred to is a great resource for solutions using KeyboardAvoidingView. Those usually give you what you need. But if you want a smooth, controlled transition between keyboard states, you should use animations. The flow would go like this:

  1. Add Keyboard event listeners to your component (keyboardDidShow and keyboardDidHide)
  2. Wrap the content you want to move in an Animated.View
  3. on keyboardDidShow, animate the y position of the Animated.View by the offset you want. The event returned (of type KeyboardEvent), along with the Dimensions API have all the measurements you need. Tip: use an Animated.timing animation with bezier Easing to control how the view moves.
  4. on keyboardDidHide, repeat the animation but in the opposite direction.

Hope this helps!

like image 164
samzmann Avatar answered Oct 06 '22 21:10

samzmann


<KeyboardAvoidingView keyboardVerticalOffset={Platform.OS === 'ios' ? 40 : 0}>
...
<KeyboardAvoidingView/>

You can try adding some offset to the view.

like image 45
Joel Avatar answered Oct 06 '22 20:10

Joel