mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-23 03:50:11 +08:00
Avoid using -[UITextView setAttributedString:] while user is typing (#19809)
Summary: iOS-specific. For languages with complex input (such as Japanese or Chinese), a user has to type multiple characters that are then merged into a single one. If `-[UITextView setAttributedString:]` is used while the user is still typing, it resets the input and characters are not being treated as typed together. This PR avoids calling this method if possible, replacing it by just copying the attributes if the string has not been changed. That preserves the state and user can continue to type Korean or Chinese characters. Fixes #19339 <!-- Required: Write your motivation here. If this PR fixes an issue, type "Fixes #issueNumber" to automatically close the issue when the PR is merged. --> <!-- Required: Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work. Bonus points for screenshots and videos! --> Essentially, the steps to reproduce are described in [the issue](https://github.com/facebook/react-native/issues/19339): 1. Type some Korean characters in TextInput, such as "하늘" (buttons `ㅎ`,`ㅏ`,`ㄴ`,`ㅡ`,`ㄹ`). 2. Then move the cursor to the beginning of the text, type "파란" (buttons `ㅍ`,`ㅏ`,`ㄹ`,`ㅏ`,`ㄴ`) this time. **Behaviour before this fix (broken)** Actual text: `ㅍㅏㄹㅏㄴ하늘`. Expected text: `파란하늘`. Characters aren't combined properly.  **Behaviour after this fix (correct)** Actual text: `파란하늘`. Expected text: `파란하늘`. Characters are combined, the same behaviour is in vanilla iOS `UITextView`.  <!-- Does this PR require a documentation change? Create a PR at https://github.com/facebook/react-native-website and add a link to it here. --> <!-- Required. Help reviewers and the release process by writing your own release notes. See below for an example. --> [IOS] [BUGFIX] [TextView] - Fix Korean/Chinese/Japanese input for multiline TextView on iOS. <!-- **INTERNAL and MINOR tagged notes will not be included in the next version's final release notes.** CATEGORY [----------] TYPE [ CLI ] [-------------] LOCATION [ DOCS ] [ BREAKING ] [-------------] [ GENERAL ] [ BUGFIX ] [ {Component} ] [ INTERNAL ] [ ENHANCEMENT ] [ {Filename} ] [ IOS ] [ FEATURE ] [ {Directory} ] |-----------| [ ANDROID ] [ MINOR ] [ {Framework} ] - | {Message} | [----------] [-------------] [-------------] |-----------| EXAMPLES: [IOS] [BREAKING] [FlatList] - Change a thing that breaks other things [ANDROID] [BUGFIX] [TextInput] - Did a thing to TextInput [CLI] [FEATURE] [local-cli/info/info.js] - CLI easier to do things with [DOCS] [BUGFIX] [GettingStarted.md] - Accidentally a thing/word [GENERAL] [ENHANCEMENT] [Yoga] - Added new yoga thing/position [INTERNAL] [FEATURE] [./scripts] - Added thing to script that nobody will see --> Pull Request resolved: https://github.com/facebook/react-native/pull/19809 Differential Revision: D13326614 Pulled By: shergin fbshipit-source-id: 6a5cab3f7290f0f623a6f4c29353a573eb321b0b
This commit is contained in:
committed by
Facebook Github Bot
parent
04af674c38
commit
f77aa4eb45
@@ -110,7 +110,21 @@ static UIColor *defaultPlaceholderColor()
|
||||
|
||||
- (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 @@ static UIColor *defaultPlaceholderColor()
|
||||
_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<NSAttributedStringKey,id> * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) {
|
||||
[textStorage setAttributes:attrs range:range];
|
||||
}];
|
||||
|
||||
[self.textStorage endEditing];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user