7

This is a react-native question for Android.

How can I handle the back button in Android when a TextInput is focused? BackHandler.addEventListener('hardwareBackPress'. () => {}) does not catch any event if TextInput is focused. It automatically dismisses the keyboard.

(Actually what I am trying to achieve is to remove the cursor when Back Button is pressed and the keyboard is dismissed)

You can play with this expo snack to understand what I am talking about:

  • No need to add the tags to the title of the question – perissf Nov 07 '18 at 16:54
  • Never add code from external links. Instead, provide a [mvce](https://stackoverflow.com/help/mcve) inside the question. Don't add the answer in the question. If the answers provided were not helpful enough, add your own answer. – perissf Nov 07 '18 at 19:57
  • Thanks for your feedback @perissf. I edited the question accordingly. I left the link to expo snack because my intention with the link is not to show the code but to allow anyone to scan the QR code with Expo app and actually see the behavior in its own Android phone. – Francisco Sarmento Nov 07 '18 at 20:40

3 Answers3

8

I believe that is the correct behavior, but to make what you want, you may detect the keyboard itself hiding instead by using Keyboard (docs at https://facebook.github.io/react-native/docs/keyboard)

import * as React from 'react';
import { Keyboard } from 'react-native';

class MyComponent extends React.Component {
  componentDidMount() {
      this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this.keyboardDidHide);
  }

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

  keyboardDidHide = () => {
      this.input.blur();
  };

    //Rest of component...

}

I prefer this method than using the onKeyPress event from TextInput because onKeyPress won't read hardware keyboard back presses, so if the user has a device with hardware back buttons, like some Android devices have, the onKeyPress won't work, this provides a more consistent experience.

Danilo
  • 216
  • 1
  • 7
  • 1
    This seems like the best workaround. Still, what I was looking for is more like an option in Android to ignore the back button handler that the keyboard seems to have, so I can be able to control the event myself. – Francisco Sarmento Nov 07 '18 at 16:56
  • That's the thing @FranciscoSarmento, I don't think you can do that in React Native directly, as this is sometimes a problem even in pure Android. When you press back and a keyboard is open, the Input Media Editor (IME for short, also known as the keyboard open) receives that press first before your app, and the only way to surpass the system is to use a listener specific for this, called onKeyPreIme. Once the IME listens to a back press, it closes itself and consumes it. Up to RN v0.57.4, there isn't a way to access this listener. – Danilo Nov 07 '18 at 17:50
  • This one worked for me perfectly! Thank you very much @Danilo! – Gabcvit Apr 06 '20 at 09:15
2

@Danilo answer does work, but it has to be applied to all text inputs. I ended up using Danilo's solution with a small twist.

Keyboard.dismiss() does blur any active TextInput, so on keyboardDidHide event I just call Keyboard.dismiss() (although the keyboard just got dismissed by pressing back button). I just need to add this to my main component.

import * as React from 'react';
import { Keyboard } from 'react-native';

class MyComponent extends React.Component {
  componentDidMount() {
      this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this.keyboardDidHide);
  }

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

  keyboardDidHide = () => {
      Keyboard.dismiss();
  };

    //Rest of component...

}

You can teste this solution in this expo snack.

In case your app has multiple TextInputs that onSubmitEditing focus the next TextInput, this is how I made it work:

  ...

  keyboardDidHide = () => {
      this.keyboardTimeout = setTimeout(() => Keyboard.dismiss(), 300)
  };

  keyboardDidShow = () => {
      clearTimeout(this.keyboardTimeout)
  };

  ...
1

You'd handle it on the TextInput itself instead of using a BackHandler. You can do this via the onKeyPress prop

constructor(props){
  super(props)
  this.inputRef = React.createRef()
}

<TextInput
  onKeyPress={({ nativeEvent }) => {
    if(nativeEvent.key === 'Backspace'){
      //your code
      // if you want to remove focus then you can use a ref
      Keyboard.dismiss();
      this.inputRef.blur()
    }
  }}
  ref={this.inputRef}
/>

Also it's important to note that on Android this event will only fire on the software keyboard, so if you're running on an emulator and use the backspace key on your computer's keyboard this will not work.

Praveen
  • 333
  • 1
  • 7
Robbie Milejczak
  • 5,664
  • 3
  • 32
  • 65