@@ -468,7 +468,9 @@ - (void)_updateState
468468- (void )_setAttributedString : (NSAttributedString *)attributedString
469469{
470470 UITextRange *selectedRange = [_backedTextInputView selectedTextRange ];
471- _backedTextInputView.attributedText = attributedString;
471+ if (![self _textOf: attributedString equals: _backedTextInputView.attributedText]) {
472+ _backedTextInputView.attributedText = attributedString;
473+ }
472474 if (_lastStringStateWasUpdatedWith.length == attributedString.length ) {
473475 // Calling `[_backedTextInputView setAttributedText]` moves caret
474476 // to the end of text input field. This cancels any selection as well
@@ -490,6 +492,38 @@ - (void)_setMultiline:(BOOL)multiline
490492 [self addSubview: _backedTextInputView];
491493}
492494
495+ - (BOOL )_textOf : (NSAttributedString *)newText equals : (NSAttributedString *)oldText
496+ {
497+ // When the dictation is running we can't update the attributed text on the backed up text view
498+ // because setting the attributed string will kill the dictation. This means that we can't impose
499+ // the settings on a dictation.
500+ // Similarly, when the user is in the middle of inputting some text in Japanese/Chinese, there will be styling on the
501+ // text that we should disregard. See
502+ // https://developer.apple.com/documentation/uikit/uitextinput/1614489-markedtextrange?language=objc for more info. If
503+ // the user added an emoji, the system adds a font attribute for the emoji and stores the original font in
504+ // NSOriginalFont. Lastly, when entering a password, etc., there will be additional styling on the field as the native
505+ // text view handles showing the last character for a split second.
506+ __block BOOL fontHasBeenUpdatedBySystem = false ;
507+ [oldText enumerateAttribute: @" NSOriginalFont"
508+ inRange: NSMakeRange (0 , oldText.length)
509+ options: 0
510+ usingBlock: ^(id value, NSRange range, BOOL *stop) {
511+ if (value) {
512+ fontHasBeenUpdatedBySystem = true ;
513+ }
514+ }];
515+
516+ BOOL shouldFallbackToBareTextComparison =
517+ [_backedTextInputView.textInputMode.primaryLanguage isEqualToString: @" dictation" ] ||
518+ _backedTextInputView.markedTextRange || _backedTextInputView.isSecureTextEntry || fontHasBeenUpdatedBySystem;
519+
520+ if (shouldFallbackToBareTextComparison) {
521+ return ([newText.string isEqualToString: oldText.string]);
522+ } else {
523+ return ([newText isEqualToAttributedString: oldText]);
524+ }
525+ }
526+
493527@end
494528
495529Class <RCTComponentViewProtocol> RCTTextInputCls (void )
0 commit comments