React-native-navigation: [IOS] Keyboard flickering while pushing screen with autofocus TextInput

Created on 1 Feb 2018  ·  22Comments  ·  Source: wix/react-native-navigation

Issue Description

Keyboard flicks while pushing screen with autofocus TextInput. Flickering appears only with default ios animation (horizontal-slide), with "fade" animation keyboard appears fine.

Steps to Reproduce / Code Snippets / Screenshots

Simply push to the navigation stack new screen with autofocus input and you'll see same keyboard flickering as on attached gif image:


Environment

  • React Native Navigation version: 1.1.365
  • React Native version: 0.51.0
  • Platform(s) (iOS, Android, or both?): IOS
  • Device info (Simulator/Device? OS version? Debug/Release?): Simulator and Device, ios 10/11, Debug and Release,

Most helpful comment

This needs to be fixed

All 22 comments

This problem happens because the second screen is mounted before the push-animation finished.
All native events (include keyboards) are share between Screens.

This issue could be solved by using fade animation or delay the TextInput from rendering too soon.

@pqkluan is there a way to have a text input autofocused and the keyboard skip animation on a new screen without a fade in or flickering?

For example, many apps have this such as Facebook messenger and others (when you select a chat, input is focused and keyboard is up on new screen before transition.

We also have this issue, it's pretty annoying that we have to delay input focusing

This needs to be fixed

Same. Adding a timeout seems to be the only fix for now.

I'm also having this issue.

No better solution besides timeout? Will be awesome if RNN itself fix this problem, because everyone could face this glitch.
Also in modals use of autoFocus makes view empty for duration of appear animation. This adds annoying delays before screen body actually showed.

The way I'm getting around it is to remove the autoFocus from the input and instead add a ref to the input, setup an event listener and focus when the screen appears:

class MyComponent extends Component {
  componentDidMount() {
    this.navigationEventListener = Navigation.events().bindComponent(this)
  }

  componentWillUnmount() {
    // Not mandatory
    if (this.navigationEventListener) {
      this.navigationEventListener.remove()
    }
  }

  componentDidAppear() {
    if (this.input) this.input.focus()
  }

  render() {
    return (
      <Input ref={ref => this.input = ref} />
    )
  }
}

componentDidMount() {
this.navigationEventListener = Navigation.events().bindComponent(this)
}

componentWillUnmount() {
// Not mandatory
if (this.navigationEventListener) {
this.navigationEventListener.remove()
}
}

componentDidAppear() {
if (this.input) this.input.focus()
}

It's not working for me.

@ATShiTou how are you creating your ref?

I had resolved my problem. Mine is showOverlay problem, not push. Thank you anyway.

@chrise86 's solution is the best for now but this is still happening for us.

Why is this closed? It's still an issue in 3.2.0

I have slightly different behavior in my app: when I push a screen with an autofocused input, the screen animates without the keyboard, then jumps back 1/4 of the screen, but now with the keyboard visible, and completes the push animation again. So it kind of jerks back and forth.

Try to set animations: {push:{waitForRender: true}} in static options=... for screen where you have autofocus input

I fixed that by

  componentDidMount() {
    this.navigationEventListener = Navigation.events().bindComponent(this);
  }

  componentWillUnmount() {
    // Not mandatory
    if (this.navigationEventListener) {
      this.navigationEventListener.remove();
    }
  }

  componentDidAppear() {
    this.input.focus();
  }

  render(){
     return <input ref={node => (this.input = node)} />
  }

@soroush-b that’s the solution I posted above. For those saying it’s still an issue, I’m not sure there is anything that can be done to “fix it” other than solutions like this. As @pqkluan said early on, it’s due to the component mounting before the native animation is complete.

Try to set animations: {push:{waitForRender: true}} in static options=... for screen where you have autofocus input

Your solution works in RNN v2.27.9, thanks!

waitForRender removed the animation entirely. As in with that configuration autofocus just stopped working. Had to use the setTimeout approach.

Still an issue in the latest versions.

The current approach that I use:

If your app is using a custom InputField:

import {useNavigationComponentDidAppear} from 'react-native-navigation-hooks';

const CustomInputField = ({shouldAutoFocus}) => {
       const inputRef = useRef(null);

       useNavigationComponentDidAppear(() => {
          if (shouldAutoFocus) {
             inputRef.current && inputRef.current.focus();
          }
       });

       return (
        <TextInput
          ref={inputRef}
          {...restProps}
        />
       )

}

And wherever you use CustomInputField: <CustomInputField shouldAutoFocus />

Old thread, I’m aware, but I thought leaving this here might help people who use functional components:

import {useNavigationComponentDidAppear} from 'react-native-navigation-hooks';

…

/**
 * Focus input once screen has appeared for the first time
 */
const inputRef = useRef(null);
const shouldAutoFocus = useRef(true);
useNavigationComponentDidAppear(() => {
  if (shouldAutoFocus.current) {
    inputRef.current?.focus();
    shouldAutoFocus.current = false;
  }
}, componentId);

…

<TextInput
  ref={inputRef}
  …
/>
Was this page helpful?
0 / 5 - 0 ratings