mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[ios]fix ios 16 auto correction highlight showing on top left corner (flutter/engine#47279)
This PR hides the system highlights in iOS 16 (except when scribble is enabled).
Note that auto correction highlight is still drawn by flutter, so it still works.
I don't think we need to CP this, since it's iOS 16 only, and iOS 17 is already out.
## Why not use system highlight?
Unlike iOS 17, the iOS 16 system highlight only respect the width provided by `firstRectForRange`, but not the height. I have audited all sizing related APIs in UITextInput (doc [here](https://developer.apple.com/documentation/uikit/uitextinput#1653155)), specifically, `firstRect(for:)`, `caretRect(for:)` and `selectionRects(for:)`, and they all return the correct height.
## About scribble
The initial implementation of `firstRectForRange` (that returns the first selection rect) was introduced for the scribble feature on iPad (code [here](1d3165a31c (diff-4c7b102c0690b8ec5e2212b079f5d69fe3f816c84e47ce94bc7bc89312f39e40R1487-R1505))).
It turns out that a non-zero rect is required for scribble's advanced feature to work (e.g. inserting a space with a vertical bar). So we can't apply this fix for scribble.
*List which issues are fixed by this PR. You must list at least one issue.*
Fixes https://github.com/flutter/flutter/issues/136802
*If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].*
[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
This commit is contained in:
parent
10c992d881
commit
058ffbe73f
@ -1690,6 +1690,16 @@ static BOOL IsSelectionRectBoundaryCloserToPoint(CGPoint point,
|
||||
}
|
||||
}
|
||||
|
||||
// The iOS 16 system highlight does not repect the height returned by `firstRectForRange`
|
||||
// API (unlike iOS 17). So we return CGRectZero to hide it (unless if scribble is enabled).
|
||||
// To support scribble's advanced gestures (e.g. insert a space with a vertical bar),
|
||||
// at least 1 character's width is required.
|
||||
if (@available(iOS 17, *)) {
|
||||
// No-op
|
||||
} else if (![self isScribbleAvailable]) {
|
||||
return CGRectZero;
|
||||
}
|
||||
|
||||
NSUInteger first = start;
|
||||
if (end < start) {
|
||||
first = end;
|
||||
|
||||
@ -1558,6 +1558,31 @@ FLUTTER_ASSERT_ARC
|
||||
[inputView firstRectForRange:range]));
|
||||
}
|
||||
|
||||
- (void)testFirstRectForRangeReturnsNoneZeroRectWhenScribbleIsEnabled {
|
||||
FlutterTextInputView* inputView = [[FlutterTextInputView alloc] initWithOwner:textInputPlugin];
|
||||
[inputView setTextInputState:@{@"text" : @"COMPOSING"}];
|
||||
|
||||
FlutterTextInputView* mockInputView = OCMPartialMock(inputView);
|
||||
OCMStub([mockInputView isScribbleAvailable]).andReturn(YES);
|
||||
|
||||
[inputView setSelectionRects:@[
|
||||
[FlutterTextSelectionRect selectionRectWithRect:CGRectMake(0, 0, 100, 100) position:0U],
|
||||
[FlutterTextSelectionRect selectionRectWithRect:CGRectMake(100, 0, 100, 100) position:1U],
|
||||
[FlutterTextSelectionRect selectionRectWithRect:CGRectMake(200, 0, 100, 100) position:2U],
|
||||
[FlutterTextSelectionRect selectionRectWithRect:CGRectMake(300, 0, 100, 100) position:3U],
|
||||
]];
|
||||
|
||||
FlutterTextRange* multiRectRange = [FlutterTextRange rangeWithNSRange:NSMakeRange(1, 3)];
|
||||
|
||||
if (@available(iOS 17, *)) {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(100, 0, 300, 100),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
} else {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(100, 0, 100, 100),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testFirstRectForRangeReturnsCorrectRectOnASingleLineLeftToRight {
|
||||
FlutterTextInputView* inputView = [[FlutterTextInputView alloc] initWithOwner:textInputPlugin];
|
||||
[inputView setTextInputState:@{@"text" : @"COMPOSING"}];
|
||||
@ -1569,8 +1594,12 @@ FLUTTER_ASSERT_ARC
|
||||
[FlutterTextSelectionRect selectionRectWithRect:CGRectMake(300, 0, 100, 100) position:3U],
|
||||
]];
|
||||
FlutterTextRange* singleRectRange = [FlutterTextRange rangeWithNSRange:NSMakeRange(1, 1)];
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(100, 0, 100, 100),
|
||||
[inputView firstRectForRange:singleRectRange]));
|
||||
if (@available(iOS 17, *)) {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(100, 0, 100, 100),
|
||||
[inputView firstRectForRange:singleRectRange]));
|
||||
} else {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectZero, [inputView firstRectForRange:singleRectRange]));
|
||||
}
|
||||
|
||||
FlutterTextRange* multiRectRange = [FlutterTextRange rangeWithNSRange:NSMakeRange(1, 3)];
|
||||
|
||||
@ -1578,8 +1607,7 @@ FLUTTER_ASSERT_ARC
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(100, 0, 300, 100),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
} else {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(100, 0, 100, 100),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectZero, [inputView firstRectForRange:multiRectRange]));
|
||||
}
|
||||
|
||||
[inputView setTextInputState:@{@"text" : @"COM"}];
|
||||
@ -1598,16 +1626,19 @@ FLUTTER_ASSERT_ARC
|
||||
[FlutterTextSelectionRect selectionRectWithRect:CGRectMake(0, 0, 100, 100) position:3U],
|
||||
]];
|
||||
FlutterTextRange* singleRectRange = [FlutterTextRange rangeWithNSRange:NSMakeRange(1, 1)];
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(200, 0, 100, 100),
|
||||
[inputView firstRectForRange:singleRectRange]));
|
||||
if (@available(iOS 17, *)) {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(200, 0, 100, 100),
|
||||
[inputView firstRectForRange:singleRectRange]));
|
||||
} else {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectZero, [inputView firstRectForRange:singleRectRange]));
|
||||
}
|
||||
|
||||
FlutterTextRange* multiRectRange = [FlutterTextRange rangeWithNSRange:NSMakeRange(1, 3)];
|
||||
if (@available(iOS 17, *)) {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(0, 0, 300, 100),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
} else {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(200, 0, 100, 100),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectZero, [inputView firstRectForRange:multiRectRange]));
|
||||
}
|
||||
|
||||
[inputView setTextInputState:@{@"text" : @"COM"}];
|
||||
@ -1630,8 +1661,12 @@ FLUTTER_ASSERT_ARC
|
||||
[FlutterTextSelectionRect selectionRectWithRect:CGRectMake(300, 100, 100, 100) position:7U],
|
||||
]];
|
||||
FlutterTextRange* singleRectRange = [FlutterTextRange rangeWithNSRange:NSMakeRange(1, 1)];
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(100, 0, 100, 100),
|
||||
[inputView firstRectForRange:singleRectRange]));
|
||||
if (@available(iOS 17, *)) {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(100, 0, 100, 100),
|
||||
[inputView firstRectForRange:singleRectRange]));
|
||||
} else {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectZero, [inputView firstRectForRange:singleRectRange]));
|
||||
}
|
||||
|
||||
FlutterTextRange* multiRectRange = [FlutterTextRange rangeWithNSRange:NSMakeRange(1, 4)];
|
||||
|
||||
@ -1639,8 +1674,7 @@ FLUTTER_ASSERT_ARC
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(100, 0, 300, 100),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
} else {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(100, 0, 100, 100),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectZero, [inputView firstRectForRange:multiRectRange]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1659,16 +1693,19 @@ FLUTTER_ASSERT_ARC
|
||||
[FlutterTextSelectionRect selectionRectWithRect:CGRectMake(0, 100, 100, 100) position:7U],
|
||||
]];
|
||||
FlutterTextRange* singleRectRange = [FlutterTextRange rangeWithNSRange:NSMakeRange(1, 1)];
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(200, 0, 100, 100),
|
||||
[inputView firstRectForRange:singleRectRange]));
|
||||
if (@available(iOS 17, *)) {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(200, 0, 100, 100),
|
||||
[inputView firstRectForRange:singleRectRange]));
|
||||
} else {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectZero, [inputView firstRectForRange:singleRectRange]));
|
||||
}
|
||||
|
||||
FlutterTextRange* multiRectRange = [FlutterTextRange rangeWithNSRange:NSMakeRange(1, 4)];
|
||||
if (@available(iOS 17, *)) {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(0, 0, 300, 100),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
} else {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(200, 0, 100, 100),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectZero, [inputView firstRectForRange:multiRectRange]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1691,8 +1728,7 @@ FLUTTER_ASSERT_ARC
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(100, -10, 300, 120),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
} else {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(100, 10, 100, 80),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectZero, [inputView firstRectForRange:multiRectRange]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1715,8 +1751,7 @@ FLUTTER_ASSERT_ARC
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(0, -10, 300, 120),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
} else {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(200, -10, 100, 120),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectZero, [inputView firstRectForRange:multiRectRange]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1739,8 +1774,7 @@ FLUTTER_ASSERT_ARC
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(100, 0, 300, 100),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
} else {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(100, 0, 100, 100),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectZero, [inputView firstRectForRange:multiRectRange]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1763,8 +1797,7 @@ FLUTTER_ASSERT_ARC
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(0, 0, 300, 100),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
} else {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(200, 0, 100, 100),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectZero, [inputView firstRectForRange:multiRectRange]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1787,8 +1820,7 @@ FLUTTER_ASSERT_ARC
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(100, 0, 400, 140),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
} else {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(100, 0, 100, 100),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectZero, [inputView firstRectForRange:multiRectRange]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1811,8 +1843,7 @@ FLUTTER_ASSERT_ARC
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(0, 0, 400, 140),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
} else {
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(300, 0, 100, 100),
|
||||
[inputView firstRectForRange:multiRectRange]));
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectZero, [inputView firstRectForRange:multiRectRange]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user