mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
iOS Text Editing Infinite Loop (#20160)
Fixes an infinite loop by eliminating an unnecessary engine/framework message.
This commit is contained in:
parent
fb19b87175
commit
69cbb2bbb8
@ -537,10 +537,7 @@ static FlutterAutofillType autofillTypeOf(NSDictionary* configuration) {
|
||||
_textInputClient = client;
|
||||
}
|
||||
|
||||
// Return true if the new input state needs to be synced back to the framework.
|
||||
// TODO(LongCatIsLooong): setTextInputState should never call updateEditingState. Sending the
|
||||
// editing value back may overwrite the framework's updated editing value.
|
||||
- (BOOL)setTextInputState:(NSDictionary*)state {
|
||||
- (void)setTextInputState:(NSDictionary*)state {
|
||||
NSString* newText = state[@"text"];
|
||||
BOOL textChanged = ![self.text isEqualToString:newText];
|
||||
if (textChanged) {
|
||||
@ -575,9 +572,6 @@ static FlutterAutofillType autofillTypeOf(NSDictionary* configuration) {
|
||||
if (textChanged) {
|
||||
[self.inputDelegate textDidChange:self];
|
||||
}
|
||||
|
||||
// For consistency with Android behavior, send an update to the framework if the text changed.
|
||||
return textChanged;
|
||||
}
|
||||
|
||||
// Extracts the selection information from the editing state dictionary.
|
||||
@ -1423,9 +1417,7 @@ static FlutterAutofillType autofillTypeOf(NSDictionary* configuration) {
|
||||
}
|
||||
|
||||
- (void)setTextInputEditingState:(NSDictionary*)state {
|
||||
if ([_activeView setTextInputState:state]) {
|
||||
[_activeView updateEditingState];
|
||||
}
|
||||
[_activeView setTextInputState:state];
|
||||
}
|
||||
|
||||
- (void)clearTextInputClient {
|
||||
|
||||
@ -16,7 +16,7 @@ FLUTTER_ASSERT_ARC
|
||||
@property(nonatomic, copy) NSString* autofillId;
|
||||
|
||||
- (void)setEditableTransform:(NSArray*)matrix;
|
||||
- (BOOL)setTextInputState:(NSDictionary*)state;
|
||||
- (void)setTextInputState:(NSDictionary*)state;
|
||||
- (void)setMarkedRect:(CGRect)markedRect;
|
||||
- (void)updateEditingState;
|
||||
- (BOOL)isVisibleToAutofill;
|
||||
@ -211,71 +211,45 @@ FLUTTER_ASSERT_ARC
|
||||
XCTAssertEqual(updateCount, 6);
|
||||
}
|
||||
|
||||
- (void)testTextChangesTriggerUpdateEditingClient {
|
||||
- (void)testTextChangesDoNotTriggerUpdateEditingClient {
|
||||
FlutterTextInputView* inputView = [[FlutterTextInputView alloc] init];
|
||||
inputView.textInputDelegate = engine;
|
||||
|
||||
__block int updateCount = 0;
|
||||
OCMStub([engine updateEditingClient:0 withState:[OCMArg isNotNil]])
|
||||
.andDo(^(NSInvocation* invocation) {
|
||||
updateCount++;
|
||||
});
|
||||
|
||||
[inputView.text setString:@"BEFORE"];
|
||||
XCTAssertEqual(updateCount, 0);
|
||||
|
||||
inputView.markedTextRange = nil;
|
||||
inputView.selectedTextRange = nil;
|
||||
XCTAssertEqual(updateCount, 1);
|
||||
|
||||
// Text changes trigger update.
|
||||
XCTAssertTrue([inputView setTextInputState:@{@"text" : @"AFTER"}]);
|
||||
// Text changes don't trigger an update.
|
||||
XCTAssertEqual(updateCount, 1);
|
||||
[inputView setTextInputState:@{@"text" : @"AFTER"}];
|
||||
XCTAssertEqual(updateCount, 1);
|
||||
[inputView setTextInputState:@{@"text" : @"AFTER"}];
|
||||
XCTAssertEqual(updateCount, 1);
|
||||
|
||||
// Don't send anything if there's nothing new.
|
||||
XCTAssertFalse([inputView setTextInputState:@{@"text" : @"AFTER"}]);
|
||||
}
|
||||
|
||||
- (void)testSelectionChangeDoesNotTriggerUpdateEditingClient {
|
||||
FlutterTextInputView* inputView = [[FlutterTextInputView alloc] init];
|
||||
inputView.textInputDelegate = engine;
|
||||
|
||||
[inputView.text setString:@"SELECTION"];
|
||||
inputView.markedTextRange = nil;
|
||||
inputView.selectedTextRange = nil;
|
||||
|
||||
BOOL shouldUpdate = [inputView
|
||||
// Selection changes don't trigger an update.
|
||||
[inputView
|
||||
setTextInputState:@{@"text" : @"SELECTION", @"selectionBase" : @0, @"selectionExtent" : @3}];
|
||||
XCTAssertFalse(shouldUpdate);
|
||||
|
||||
shouldUpdate = [inputView
|
||||
XCTAssertEqual(updateCount, 1);
|
||||
[inputView
|
||||
setTextInputState:@{@"text" : @"SELECTION", @"selectionBase" : @1, @"selectionExtent" : @3}];
|
||||
XCTAssertFalse(shouldUpdate);
|
||||
XCTAssertEqual(updateCount, 1);
|
||||
|
||||
shouldUpdate = [inputView
|
||||
setTextInputState:@{@"text" : @"SELECTION", @"selectionBase" : @1, @"selectionExtent" : @2}];
|
||||
XCTAssertFalse(shouldUpdate);
|
||||
|
||||
// Don't send anything if there's nothing new.
|
||||
shouldUpdate = [inputView
|
||||
setTextInputState:@{@"text" : @"SELECTION", @"selectionBase" : @1, @"selectionExtent" : @2}];
|
||||
XCTAssertFalse(shouldUpdate);
|
||||
}
|
||||
|
||||
- (void)testComposingChangeDoesNotTriggerUpdateEditingClient {
|
||||
FlutterTextInputView* inputView = [[FlutterTextInputView alloc] init];
|
||||
inputView.textInputDelegate = engine;
|
||||
|
||||
// Reset to test marked text.
|
||||
[inputView.text setString:@"COMPOSING"];
|
||||
inputView.markedTextRange = nil;
|
||||
inputView.selectedTextRange = nil;
|
||||
|
||||
BOOL shouldUpdate = [inputView
|
||||
setTextInputState:@{@"text" : @"COMPOSING", @"composingBase" : @0, @"composingExtent" : @3}];
|
||||
XCTAssertFalse(shouldUpdate);
|
||||
|
||||
shouldUpdate = [inputView
|
||||
// Composing region changes don't trigger an update.
|
||||
[inputView
|
||||
setTextInputState:@{@"text" : @"COMPOSING", @"composingBase" : @1, @"composingExtent" : @2}];
|
||||
XCTAssertEqual(updateCount, 1);
|
||||
[inputView
|
||||
setTextInputState:@{@"text" : @"COMPOSING", @"composingBase" : @1, @"composingExtent" : @3}];
|
||||
XCTAssertFalse(shouldUpdate);
|
||||
|
||||
shouldUpdate = [inputView
|
||||
setTextInputState:@{@"text" : @"COMPOSING", @"composingBase" : @1, @"composingExtent" : @2}];
|
||||
XCTAssertFalse(shouldUpdate);
|
||||
|
||||
shouldUpdate = [inputView
|
||||
setTextInputState:@{@"text" : @"COMPOSING", @"composingBase" : @1, @"composingExtent" : @2}];
|
||||
XCTAssertFalse(shouldUpdate);
|
||||
XCTAssertEqual(updateCount, 1);
|
||||
}
|
||||
|
||||
- (void)testUITextInputAvoidUnnecessaryUndateEditingClientCalls {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user