|
22 | 22 | static constexpr double kUITextInputAccessibilityEnablingDelaySeconds = 0.5;
|
23 | 23 |
|
24 | 24 | // A delay before reenabling the UIView areAnimationsEnabled to YES
|
25 |
| -// in order for becomeFirstResponder to receive the proper value |
| 25 | +// in order for becomeFirstResponder to receive the proper value. |
26 | 26 | static const NSTimeInterval kKeyboardAnimationDelaySeconds = 0.1;
|
27 | 27 |
|
| 28 | +// A time set for the screenshot to animate back to the assigned position. |
| 29 | +static const NSTimeInterval kKeyboardAnimationTimeToCompleteion = 0.3; |
| 30 | + |
28 | 31 | // The "canonical" invalid CGRect, similar to CGRectNull, used to
|
29 | 32 | // indicate a CGRect involved in firstRectForRange calculation is
|
30 | 33 | // invalid. The specific value is chosen so that if firstRectForRange
|
@@ -2234,6 +2237,8 @@ @interface FlutterTextInputPlugin ()
|
2234 | 2237 | @property(nonatomic, strong) UIView* keyboardView;
|
2235 | 2238 | @property(nonatomic, strong) UIView* cachedFirstResponder;
|
2236 | 2239 | @property(nonatomic, assign) CGRect keyboardRect;
|
| 2240 | +@property(nonatomic, assign) CGFloat previousPointerYPosition; |
| 2241 | +@property(nonatomic, assign) CGFloat pointerYVelocity; |
2237 | 2242 | @end
|
2238 | 2243 |
|
2239 | 2244 | @implementation FlutterTextInputPlugin {
|
@@ -2340,28 +2345,32 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
|
2340 | 2345 | }
|
2341 | 2346 |
|
2342 | 2347 | - (void)handlePointerUp:(CGFloat)pointerY {
|
2343 |
| - // View must be loaded at this point. |
2344 |
| - UIScreen* screen = _viewController.flutterScreenIfViewLoaded; |
2345 |
| - CGFloat screenHeight = screen.bounds.size.height; |
2346 |
| - CGFloat keyboardHeight = _keyboardRect.size.height; |
2347 |
| - BOOL shouldDismissKeyboard = (screenHeight - (keyboardHeight / 2)) < pointerY; |
2348 |
| - [UIView animateWithDuration:0.3f |
2349 |
| - animations:^{ |
2350 |
| - double keyboardDestination = |
2351 |
| - shouldDismissKeyboard ? screenHeight : screenHeight - keyboardHeight; |
2352 |
| - _keyboardViewContainer.frame = CGRectMake( |
2353 |
| - 0, keyboardDestination, _viewController.flutterScreenIfViewLoaded.bounds.size.width, |
2354 |
| - _keyboardViewContainer.frame.size.height); |
2355 |
| - } |
2356 |
| - completion:^(BOOL finished) { |
2357 |
| - if (shouldDismissKeyboard) { |
2358 |
| - [self.textInputDelegate flutterTextInputView:self.activeView |
2359 |
| - didResignFirstResponderWithTextInputClient:self.activeView.textInputClient]; |
2360 |
| - [self dismissKeyboardScreenshot]; |
2361 |
| - } else { |
2362 |
| - [self showKeyboardAndRemoveScreenshot]; |
| 2348 | + if (_keyboardView.superview != nil) { |
| 2349 | + // Done to avoid the issue of a pointer up done without a screenshot |
| 2350 | + // View must be loaded at this point. |
| 2351 | + UIScreen* screen = _viewController.flutterScreenIfViewLoaded; |
| 2352 | + CGFloat screenHeight = screen.bounds.size.height; |
| 2353 | + CGFloat keyboardHeight = _keyboardRect.size.height; |
| 2354 | + // Negative velocity indicates a downward movement |
| 2355 | + BOOL shouldDismissKeyboardBasedOnVelocity = _pointerYVelocity < 0; |
| 2356 | + [UIView animateWithDuration:kKeyboardAnimationTimeToCompleteion |
| 2357 | + animations:^{ |
| 2358 | + double keyboardDestination = |
| 2359 | + shouldDismissKeyboardBasedOnVelocity ? screenHeight : screenHeight - keyboardHeight; |
| 2360 | + _keyboardViewContainer.frame = CGRectMake( |
| 2361 | + 0, keyboardDestination, _viewController.flutterScreenIfViewLoaded.bounds.size.width, |
| 2362 | + _keyboardViewContainer.frame.size.height); |
2363 | 2363 | }
|
2364 |
| - }]; |
| 2364 | + completion:^(BOOL finished) { |
| 2365 | + if (shouldDismissKeyboardBasedOnVelocity) { |
| 2366 | + [self.textInputDelegate flutterTextInputView:self.activeView |
| 2367 | + didResignFirstResponderWithTextInputClient:self.activeView.textInputClient]; |
| 2368 | + [self dismissKeyboardScreenshot]; |
| 2369 | + } else { |
| 2370 | + [self showKeyboardAndRemoveScreenshot]; |
| 2371 | + } |
| 2372 | + }]; |
| 2373 | + } |
2365 | 2374 | }
|
2366 | 2375 |
|
2367 | 2376 | - (void)dismissKeyboardScreenshot {
|
@@ -2395,13 +2404,16 @@ - (void)handlePointerMove:(CGFloat)pointerY {
|
2395 | 2404 | [self hideKeyboardWithoutAnimationAndAvoidCursorDismissUpdate];
|
2396 | 2405 | } else {
|
2397 | 2406 | [self setKeyboardContainerHeight:pointerY];
|
| 2407 | + _pointerYVelocity = _previousPointerYPosition - pointerY; |
2398 | 2408 | }
|
2399 | 2409 | } else {
|
2400 | 2410 | if (_keyboardView.superview != nil) {
|
2401 | 2411 | // Keeps keyboard at proper height.
|
2402 | 2412 | _keyboardViewContainer.frame = _keyboardRect;
|
| 2413 | + _pointerYVelocity = _previousPointerYPosition - pointerY; |
2403 | 2414 | }
|
2404 | 2415 | }
|
| 2416 | + _previousPointerYPosition = pointerY; |
2405 | 2417 | }
|
2406 | 2418 |
|
2407 | 2419 | - (void)setKeyboardContainerHeight:(CGFloat)pointerY {
|
|
0 commit comments