@@ -69,11 +69,11 @@ @interface FlutterViewController () <FlutterBinaryMessenger, UIScrollViewDelegat
6969/* *
7070 * Keyboard animation properties
7171 */
72- @property (nonatomic , assign ) double targetViewInsetBottom;
72+ @property (nonatomic , assign ) CGFloat targetViewInsetBottom;
73+ @property (nonatomic , assign ) CGFloat originalViewInsetBottom;
7374@property (nonatomic , retain ) VSyncClient* keyboardAnimationVSyncClient;
7475@property (nonatomic , assign ) BOOL keyboardAnimationIsShowing;
7576@property (nonatomic , assign ) fml::TimePoint keyboardAnimationStartTime;
76- @property (nonatomic , assign ) CGFloat originalViewInsetBottom;
7777@property (nonatomic , assign ) BOOL isKeyboardInOrTransitioningFromBackground;
7878
7979// / VSyncClient for touch events delivery frame rate correction.
@@ -574,8 +574,8 @@ - (void)installFirstFrameCallback {
574574 // Start on the platform thread.
575575 weakPlatformView->SetNextFrameCallback ([weakSelf = [self getWeakPtr ],
576576 platformTaskRunner = [_engine.get () platformTaskRunner ],
577- RasterTaskRunner = [_engine.get () RasterTaskRunner ]]() {
578- FML_DCHECK (RasterTaskRunner ->RunsTasksOnCurrentThread ());
577+ rasterTaskRunner = [_engine.get () rasterTaskRunner ]]() {
578+ FML_DCHECK (rasterTaskRunner ->RunsTasksOnCurrentThread ());
579579 // Get callback on raster thread and jump back to platform thread.
580580 platformTaskRunner->PostTask ([weakSelf]() {
581581 if (weakSelf) {
@@ -1596,7 +1596,55 @@ - (void)startKeyBoardAnimation:(NSTimeInterval)duration {
15961596
15971597 // Invalidate old vsync client if old animation is not completed.
15981598 [self invalidateKeyboardAnimationVSyncClient ];
1599- [self setupKeyboardAnimationVsyncClient ];
1599+
1600+ fml::WeakPtr<FlutterViewController> weakSelf = [self getWeakPtr ];
1601+ FlutterKeyboardAnimationCallback keyboardAnimationCallback = ^(
1602+ fml::TimePoint keyboardAnimationTargetTime) {
1603+ if (!weakSelf) {
1604+ return ;
1605+ }
1606+ fml::scoped_nsobject<FlutterViewController> flutterViewController (
1607+ [(FlutterViewController*)weakSelf.get () retain ]);
1608+ if (!flutterViewController) {
1609+ return ;
1610+ }
1611+
1612+ // If the view controller's view is not loaded, bail out.
1613+ if (!flutterViewController.get ().isViewLoaded ) {
1614+ return ;
1615+ }
1616+ // If the view for tracking keyboard animation is nil, means it is not
1617+ // created, bail out.
1618+ if ([flutterViewController keyboardAnimationView ] == nil ) {
1619+ return ;
1620+ }
1621+ // If keyboardAnimationVSyncClient is nil, means the animation ends.
1622+ // And should bail out.
1623+ if (flutterViewController.get ().keyboardAnimationVSyncClient == nil ) {
1624+ return ;
1625+ }
1626+
1627+ if ([flutterViewController keyboardAnimationView ].superview == nil ) {
1628+ // Ensure the keyboardAnimationView is in view hierarchy when animation running.
1629+ [flutterViewController.get ().view addSubview: [flutterViewController keyboardAnimationView ]];
1630+ }
1631+
1632+ if ([flutterViewController keyboardSpringAnimation ] == nil ) {
1633+ if (flutterViewController.get ().keyboardAnimationView .layer .presentationLayer ) {
1634+ flutterViewController.get ()->_viewportMetrics .physical_view_inset_bottom =
1635+ flutterViewController.get ()
1636+ .keyboardAnimationView .layer .presentationLayer .frame .origin .y ;
1637+ [flutterViewController updateViewportMetricsIfNeeded ];
1638+ }
1639+ } else {
1640+ fml::TimeDelta timeElapsed =
1641+ keyboardAnimationTargetTime - flutterViewController.get ().keyboardAnimationStartTime ;
1642+ flutterViewController.get ()->_viewportMetrics .physical_view_inset_bottom =
1643+ [[flutterViewController keyboardSpringAnimation ] curveFunction: timeElapsed.ToSecondsF ()];
1644+ [flutterViewController updateViewportMetricsIfNeeded ];
1645+ }
1646+ };
1647+ [self setupKeyboardAnimationVsyncClient: keyboardAnimationCallback];
16001648 VSyncClient* currentVsyncClient = _keyboardAnimationVSyncClient;
16011649
16021650 [UIView animateWithDuration: duration
@@ -1639,45 +1687,28 @@ - (void)setupKeyboardSpringAnimationIfNeeded:(CAAnimation*)keyboardAnimation {
16391687 toValue: self .targetViewInsetBottom]);
16401688}
16411689
1642- - (void )setupKeyboardAnimationVsyncClient {
1643- auto callback = [weakSelf =
1644- [self getWeakPtr ]](std::unique_ptr<flutter::FrameTimingsRecorder> recorder) {
1645- if (!weakSelf) {
1646- return ;
1647- }
1648- fml::scoped_nsobject<FlutterViewController> flutterViewController (
1649- [(FlutterViewController*)weakSelf.get () retain ]);
1650- if (!flutterViewController) {
1651- return ;
1652- }
1653-
1654- if ([flutterViewController keyboardAnimationView ].superview == nil ) {
1655- // Ensure the keyboardAnimationView is in view hierarchy when animation running.
1656- [flutterViewController.get ().view addSubview: [flutterViewController keyboardAnimationView ]];
1657- }
1658-
1659- if ([flutterViewController keyboardSpringAnimation ] == nil ) {
1660- if (flutterViewController.get ().keyboardAnimationView .layer .presentationLayer ) {
1661- flutterViewController.get ()->_viewportMetrics .physical_view_inset_bottom =
1662- flutterViewController.get ()
1663- .keyboardAnimationView .layer .presentationLayer .frame .origin .y ;
1664- [flutterViewController updateViewportMetricsIfNeeded ];
1665- }
1666- } else {
1667- fml::TimeDelta timeElapsed = recorder.get ()->GetVsyncTargetTime () -
1668- flutterViewController.get ().keyboardAnimationStartTime ;
1669-
1670- flutterViewController.get ()->_viewportMetrics .physical_view_inset_bottom =
1671- [[flutterViewController keyboardSpringAnimation ] curveFunction: timeElapsed.ToSecondsF ()];
1672- [flutterViewController updateViewportMetricsIfNeeded ];
1673- }
1674- };
1675- flutter::Shell& shell = [_engine.get () shell ];
1690+ - (void )setupKeyboardAnimationVsyncClient :
1691+ (FlutterKeyboardAnimationCallback)keyboardAnimationCallback {
1692+ if (!keyboardAnimationCallback) {
1693+ return ;
1694+ }
16761695 NSAssert (_keyboardAnimationVSyncClient == nil ,
16771696 @" _keyboardAnimationVSyncClient must be nil when setup" );
1678- _keyboardAnimationVSyncClient =
1679- [[VSyncClient alloc ] initWithTaskRunner: shell.GetTaskRunners ().GetPlatformTaskRunner ()
1680- callback: callback];
1697+
1698+ // Make sure the new viewport metrics get sent after the begin frame event has processed.
1699+ fml::scoped_nsprotocol<FlutterKeyboardAnimationCallback> animationCallback (
1700+ [keyboardAnimationCallback copy ]);
1701+ auto uiCallback = [animationCallback,
1702+ engine = _engine](std::unique_ptr<flutter::FrameTimingsRecorder> recorder) {
1703+ fml::TimeDelta frameInterval = recorder->GetVsyncTargetTime () - recorder->GetVsyncStartTime ();
1704+ fml::TimePoint keyboardAnimationTargetTime = recorder->GetVsyncTargetTime () + frameInterval;
1705+ [engine platformTaskRunner ]->PostTask ([animationCallback, keyboardAnimationTargetTime] {
1706+ animationCallback.get ()(keyboardAnimationTargetTime);
1707+ });
1708+ };
1709+
1710+ _keyboardAnimationVSyncClient = [[VSyncClient alloc ] initWithTaskRunner: [_engine uiTaskRunner ]
1711+ callback: uiCallback];
16811712 _keyboardAnimationVSyncClient.allowPauseAfterVsync = NO ;
16821713 [_keyboardAnimationVSyncClient await ];
16831714}
0 commit comments