Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iOS Dictation TextInput ends abruptly between words #18890

Closed
3 tasks done
sedevccb opened this issue Apr 16, 2018 · 18 comments
Closed
3 tasks done

iOS Dictation TextInput ends abruptly between words #18890

sedevccb opened this issue Apr 16, 2018 · 18 comments
Labels
Component: TextInput Related to the TextInput component. Platform: iOS iOS applications. Stale There has been a lack of activity on this issue and it may be closed soon.

Comments

@sedevccb
Copy link

When using dictation on a TextInput in iOS, the dictation will end abruptly between words. This was not an issue previously on React Native 53. Moving to version 54+ causes this behavior.

Environment

Environment:
OS: macOS High Sierra 10.13.4
Node: 9.7.1
Yarn: 1.5.1
npm: 5.6.0
Watchman: Not Found
Xcode: Xcode 9.3 Build version 9E145
Android Studio: Not Found

Packages: (wanted => installed)
react: 16.3.0-alpha.1 => 16.3.0-alpha.1
react-native: https://github.com/expo/react-native/archive/sdk-26.0.0.tar.gz => 0.54.2

Steps to Reproduce

Try using iOS dictation in the TextInput. Be sure to use a long sentence...

import React from 'react';
import { TextInput } from 'react-native';

export default class App extends React.Component {
  state = { value: '' }
  onChangeText = value => console.log(value) || this.setState({ value })
  render() {
    return (
        <TextInput
          onChangeText={this.onChangeText}
          value={this.state.value}
          style={{ borderWidth: 2, borderColor: 'black', width: 200, height: 48 }}
        />
    );
  }
}

Expected Behavior

I expect the TextInput to capture the entire dictation.

Actual Behavior

The dictation will end abruptly between words.

@react-native-bot react-native-bot added Platform: iOS iOS applications. Component: TextInput Related to the TextInput component. labels Apr 16, 2018
@marcosrdz
Copy link

If I place a breakpoint on setAttributedText (line 101) on this file:

react-native/Libraries/Text/TextInput/RCTBaseTextInputView.m

and wait a second or two, then resume the app, the dictated sentence does not get cut off.

@marcosrdz
Copy link

Hmm...after additional debugging, seems like the text inserted by the dictation works “too fast” for setState. If i move the onChangeText to onBlur, it doesn’t get cut off.

@gancan110
Copy link

I have this problem too. Is that a problem? Or are you ready to use the onBlur method to get the data that is being entered by Textinput? Version 0.49.2 is fine, but 0.55 will also appear.

@lbelavoir
Copy link

@marcosrdz moving setState in onBlur will make useless all the other props such as onEndEditing or onSubmitEditing because they will fire before setState take the previous state

@arvidkahl
Copy link

I have solved this issue using lodash.debounce.

import _ from 'lodash'

class SomeComponent extends React.Component {
  
  constructor(props){
    super(props);
    this.state = {
      text: ''
    }
    this.onChangeTextDelayed = _.debounce(this.onChangeText.bind(this), 1500)
  }
  
  onChangeText(text) {
    this.setState({text})
  }

  render() {
    return (
      <TextInput
        onBlur={()=>{
          this.onChangeTextDelayed.flush()
        }}
        onChangeText={this.onChangeTextDelayed}
        value={this.state.text}
      />
    )
  }
}

As the debounce needs to be invoked immediately after the user stops editing (voice or text), the .flush method of the debounced function needs to be called in the onBlur handler.

You might need to tweak the debounce timeout, but I've found anything between 1 and 2 sec to be useable for dictation.

@eoinnorris
Copy link
Contributor

The fix in react native is merely disguising the problem. The underlying problem is that when the setAttributedText method in RCTBaseTextInputView.m is called it does two main things:

  1. Check that the attributed text that it receives is equal to the existing attributed text in the underlying backed up view ( backedTextInputView)
  2. If not set the attributed text of the backed up view to the value passed into the method. This kills the dictation as it is effectively the equivalent of typing in the backed up text view.
    self.backedTextInputView.attributedText = attributedText;

is the problem. It kills the dictation. It may have other effects as well.

In all cases I have seen the underlying text of the attributed string that is passed in the same as the text in the backedTextInputView, what was said to the dictation; however the attributes are different, which causes the isEqualToAttributedString: check to fail and thus the update happens, and the keyboard is killed.

(No doubt this is to impose whatever properties were set in the JS layer to the underlying text view)

The debounce above will stop this method being called for 1.5 seconds, which fixes it for that length of time only.

@pranavbidchat
Copy link

I also faced the same issue. You can use shouldComponentUpdate to not re-render that text input component while setting the state.

@SudoPlz
Copy link
Contributor

SudoPlz commented Jun 12, 2018

The js solution above does not work if you rely on onChangeText heavily and use something like redux.

Sometimes the onBlur function flushes the debounce method before the new value has been set in redux via onChangeText.

We found out that's the case the hard way (by having people type stuff, and even though it shows on screen, the submitted text was less than what they had typed...

We need to think of a better solution.

@SudoPlz
Copy link
Contributor

SudoPlz commented Jun 12, 2018

Fixed the issue by debouncing the value change and not the onChangeText callback.

Here's the fully operational component --> https://gist.github.com/SudoPlz/4c35ca33af44d8ac998d836fb4552627

@ashokseervidev
Copy link

ashokseervidev commented Jun 27, 2018

Any other better solution with in iOS itself?

Our App is broken in production because of this issue. Any ETA when @react-native-community going to take it up. @SudoPlz

@ashokseervidev
Copy link

ashokseervidev commented Jun 28, 2018

Any updates @shergin

@eoinnorris
Copy link
Contributor

@AshokICreate have you tried the potential fix I linked?

@nikodunk
Copy link

nikodunk commented Aug 8, 2018

Same issue here, cut off after 1 minute of dictation.

@ashokseervidev
Copy link

i down graded react-native to 0.53 to make it work.

@stephen-puiszis
Copy link

stephen-puiszis commented Sep 21, 2018

FWIW I ran into the same frustrating issue with onChangeText. I managed to get a work-able solution using @arvidkahl's _.debounce approach.

It's not perfect and I'm looking for, and expecting edge cases to arise but it will at least provide a somewhat usable experience, especially for those users who must navigate apps with core iOS and Android accessibility features.

#18890 (comment)

@Jackman3005
Copy link

It looks like this may have been fixed in 0.57.x. Here is a detailed analysis of why this bug occurs.

We tried upgrading to 0.57.1 but ran into some issues and bailed out. The work around we found for now, is to type anything into the text box first, then dictation can be used normally without it exiting. Weird that the bug only exhibits itself when the text box is empty...

Would be nice to confirm that it for sure works in 0.57.x.

Hope this helps!

@stale
Copy link

stale bot commented Dec 24, 2018

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as "For Discussion" or "Good first issue" and I will leave it open. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Dec 24, 2018
@stale
Copy link

stale bot commented Dec 31, 2018

Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please feel free to create a new issue with up-to-date information.

@stale stale bot closed this as completed Dec 31, 2018
@facebook facebook locked as resolved and limited conversation to collaborators Jan 1, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Component: TextInput Related to the TextInput component. Platform: iOS iOS applications. Stale There has been a lack of activity on this issue and it may be closed soon.
Projects
None yet
Development

No branches or pull requests