Source:  Twitter logo

I'm working on a React Native app and many screens has forms with text input fields.

When I press the text input, the keyboard opens. I created a floating InputAccessory component which appears at the top of the keyboard to dismiss it, with the button "Done" on it.

However now that I have this accessory, when I click an input field or press the "Next" button on the keyboard to go to the next field, the ScrollView scrolls to align the bottom of the text input with the top of the keyboard. With this floating accessory it poses problems as you can see below you can't see the content of the text input because of this accessory, and I'd like to have the scrollview scrolling a bit more to display the entire text input.

I could probably do the calculation for this and run the .scrollTo() method from the ScrollView component but this pattern is very common to my entire app and I'm looking for an elegant solution that could be generic enough every single time I import a text input and focus on it.

Do you have any suggestion?

Thanks

I got the same issue before and i have 2 different solutions , Both of them worked for me.

1- Using react-native-keyboard-aware-scroll-view , Note that this library will already contain scrollView so you remove your own scroll view and use

<KeyboardAwareScrollView>
  <View>
    <TextInput />
  </View>
</KeyboardAwareScrollView>

You can also check documentation for more info.

This solution is easier as you don't need to handle anything by yourself, but i think you will have some issues if you want to include scrollView inside it.


2- I once created a component AvoidKeyboard that actually does something similar to your solution, but it used to translate top the whole view with the keyboard height value, this solution worked perfectly also for me.

Implementation

import React, { Component } from 'react';
import { Animated, Easing, Keyboard } from 'react-native';
import PropTypes from 'prop-types';


class AvoidKeyboard extends Component {
  constructor(props) {
    super(props);
    this.state = {
      animatedViewHeight: new Animated.Value(0),
      viewHeight: 0,
    };

    this.setViewHeightOnce = this.setViewHeightOnce.bind(this);
    this.keyboardWillShow = this.keyboardWillShow.bind(this);
    this.keyboardWillHide = this.keyboardWillHide.bind(this);
    this.keyboardDidShowListener = Keyboard.addListener('keyboardWillShow', this.keyboardWillShow);
    this.keyboardDidHideListener = Keyboard.addListener('keyboardWillHide', this.keyboardWillHide);
  }

  componentWillUnmount() {
    this.keyboardDidShowListener && this.keyboardDidShowListener.remove();
    this.keyboardDidHideListener && this.keyboardDidHideListener.remove();
  }

  setViewHeightOnce(event) {
    const { height } = event.nativeEvent.layout;
    if (this.state.viewHeight === 0) {
      const avoidPaddingBottom = 15;
      this.setState({
        viewHeight: height + avoidPaddingBottom,
        animatedViewHeight: new Animated.Value(height + avoidPaddingBottom),
      });
    }
  }

  keyboardWillShow(e) {
    const { viewHeight } = this.state;
    if (viewHeight) {
      requestAnimationFrame(() => { // eslint-disable-line no-undef
        Animated.timing(this.state.animatedViewHeight, {
          toValue: (viewHeight - e.endCoordinates.height),
          duration: 200,
          delay: 0,
          easing: Easing.inOut(Easing.ease),
        }).start();
      });
    }
  }

  keyboardWillHide() {
    requestAnimationFrame(() => { // eslint-disable-line no-undef
      Animated.timing(this.state.animatedViewHeight, {
        toValue: this.state.viewHeight,
        duration: 200,
        delay: 0,
        easing: Easing.inOut(Easing.ease),
      }).start();
    });
  }

  render() {
    let animatedHeight;
    const { viewHeight } = this.state;
    if (viewHeight > 0) {
      animatedHeight = { maxHeight: this.state.animatedViewHeight };
    }
    return (
      <Animated.View
        style={[{ flex: 1, justifyContent: 'flex-end' }, animatedHeight]}
        onLayout={this.setViewHeightOnce}
      >
        {this.props.children}
      </Animated.View>
    );
  }
}


AvoidKeyboard.propTypes = {
  children: PropTypes.node.isRequired,
};


export default AvoidKeyboard;

Now you just need to wrap your component or screen inside AvoidKeyboard and your screen height will shrink once keyboard is open, and you will be able to scroll the screen

10 users liked answer #0dislike answer #010
Amr Labib profile pic
Amr Labib

I have had a lot of problems with keyboard in IOS. No KeyboardSpacer, react-native-keyboard-aware-scroll-view and more packages solved it.

Recently I discovered react-native-keyboard-manager and it solved all my problems without one line of code, also in modals and more (I don't have nothing to do with the author, but this package saved me the day). Give it a change.

4 users liked answer #1dislike answer #14
user2848017 profile pic
user2848017

I found a solution which doesn't involve hacky animation change.

When the keyboard opens, what I decided to do is to add some margin at the bottom of the ScrollView which correspond to the height of the InputAccessory. I then remove this margin when the keyboard closes. It looks like something like this:

import KeyboardListener from 'react-native-keyboard-listener';

...
render() [
  <ScrollView 
    key={1} 
    style={{ marginBottom: this.state.scrollViewMarginBottom }} 
  />,
  <InputAccessory key={2} onLayout={...} />,
  <KeyboardListener
    key={3}
    onWillShow={() => this.setState({ scrollViewMarginBottom: inputAccessoryHeight });
    onWillHide={() => this.setState({ scrollViewMarginBottom: 0 })
  />
]
2 users liked answer #2dislike answer #22
alexmngn profile pic
alexmngn

I was facing the same issue and reading online I figured out the following solution

For Android

Go to your AndroidManifest.xml and add android:windowSoftInputMode="adjustPan"

<activity
        android:name=".MainActivity"
        android:windowSoftInputMode="adjustPan">
        .....
</activity>

For IOS

Just follow the instructions in this repo. https://github.com/douglasjunior/react-native-keyboard-manager.

Hope this helps. :)

2 users liked answer #3dislike answer #32
Sandeep Ranjan profile pic
Sandeep Ranjan

Copyright © 2022 QueryThreads

All content on Query Threads is licensed under the Creative Commons Attribution-ShareAlike 3.0 license (CC BY-SA 3.0).