From 2a08ae344b7f119c0e3bb0053eed242b3fea56dc Mon Sep 17 00:00:00 2001 From: Igor Mandrigin Date: Tue, 19 Jun 2018 18:15:33 +0200 Subject: [PATCH] Avoid using `-[UITextView setAttributedString:]` while user is typing text. For languages with complex input (such as Japanese or Chinese), where user presses multiple buttons to input one symbol, it breaks selection and input, so it is impossible to enter characters. --- .../Text/TextInput/Multiline/RCTUITextView.m | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/Libraries/Text/TextInput/Multiline/RCTUITextView.m b/Libraries/Text/TextInput/Multiline/RCTUITextView.m index ddfd1c27f50d7b..7fc080a737f8c7 100644 --- a/Libraries/Text/TextInput/Multiline/RCTUITextView.m +++ b/Libraries/Text/TextInput/Multiline/RCTUITextView.m @@ -110,7 +110,21 @@ - (void)setTextAlignment:(NSTextAlignment)textAlignment - (void)setAttributedText:(NSAttributedString *)attributedText { - [super setAttributedText:attributedText]; + // Using `setAttributedString:` while user is typing breaks some internal mechanics + // when entering complex input languages such as Chinese, Korean or Japanese. + // see: https://github.com/facebook/react-native/issues/19339 + + // We try to avoid calling this method as much as we can. + // If the text has changed, there is nothing we can do. + if (![super.attributedText.string isEqualToString:attributedText.string]) { + [super setAttributedText:attributedText]; + } else { + // But if the text is preserved, we just copying the attributes from the source string. + if (![super.attributedText isEqualToAttributedString:attributedText]) { + [self copyTextAttributesFrom:attributedText]; + } + } + [self textDidChange]; } @@ -241,4 +255,20 @@ - (void)invalidatePlaceholderVisibility _placeholderView.hidden = !isVisible; } +#pragma mark - Utility Methods + +- (void)copyTextAttributesFrom:(NSAttributedString *)sourceString +{ + [self.textStorage beginEditing]; + + NSTextStorage *textStorage = self.textStorage; + [sourceString enumerateAttributesInRange:NSMakeRange(0, sourceString.length) + options:NSAttributedStringEnumerationReverse + usingBlock:^(NSDictionary * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) { + [textStorage setAttributes:attrs range:range]; + }]; + + [self.textStorage endEditing]; +} + @end