@@ -468,7 +468,9 @@ - (void)_updateState
468
468
- (void )_setAttributedString : (NSAttributedString *)attributedString
469
469
{
470
470
UITextRange *selectedRange = [_backedTextInputView selectedTextRange ];
471
- _backedTextInputView.attributedText = attributedString;
471
+ if (![self _textOf: attributedString equals: _backedTextInputView.attributedText]) {
472
+ _backedTextInputView.attributedText = attributedString;
473
+ }
472
474
if (_lastStringStateWasUpdatedWith.length == attributedString.length ) {
473
475
// Calling `[_backedTextInputView setAttributedText]` moves caret
474
476
// to the end of text input field. This cancels any selection as well
@@ -490,6 +492,38 @@ - (void)_setMultiline:(BOOL)multiline
490
492
[self addSubview: _backedTextInputView];
491
493
}
492
494
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
+
493
527
@end
494
528
495
529
Class <RCTComponentViewProtocol> RCTTextInputCls (void )
0 commit comments