@@ -69,11 +69,11 @@ @interface FlutterViewController () <FlutterBinaryMessenger, UIScrollViewDelegat
69
69
/* *
70
70
* Keyboard animation properties
71
71
*/
72
- @property (nonatomic , assign ) double targetViewInsetBottom;
72
+ @property (nonatomic , assign ) CGFloat targetViewInsetBottom;
73
+ @property (nonatomic , assign ) CGFloat originalViewInsetBottom;
73
74
@property (nonatomic , retain ) VSyncClient* keyboardAnimationVSyncClient;
74
75
@property (nonatomic , assign ) BOOL keyboardAnimationIsShowing;
75
76
@property (nonatomic , assign ) fml::TimePoint keyboardAnimationStartTime;
76
- @property (nonatomic , assign ) CGFloat originalViewInsetBottom;
77
77
@property (nonatomic , assign ) BOOL isKeyboardInOrTransitioningFromBackground;
78
78
79
79
// / VSyncClient for touch events delivery frame rate correction.
@@ -574,8 +574,8 @@ - (void)installFirstFrameCallback {
574
574
// Start on the platform thread.
575
575
weakPlatformView->SetNextFrameCallback ([weakSelf = [self getWeakPtr ],
576
576
platformTaskRunner = [_engine.get () platformTaskRunner ],
577
- RasterTaskRunner = [_engine.get () RasterTaskRunner ]]() {
578
- FML_DCHECK (RasterTaskRunner ->RunsTasksOnCurrentThread ());
577
+ rasterTaskRunner = [_engine.get () rasterTaskRunner ]]() {
578
+ FML_DCHECK (rasterTaskRunner ->RunsTasksOnCurrentThread ());
579
579
// Get callback on raster thread and jump back to platform thread.
580
580
platformTaskRunner->PostTask ([weakSelf]() {
581
581
if (weakSelf) {
@@ -1596,7 +1596,55 @@ - (void)startKeyBoardAnimation:(NSTimeInterval)duration {
1596
1596
1597
1597
// Invalidate old vsync client if old animation is not completed.
1598
1598
[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];
1600
1648
VSyncClient* currentVsyncClient = _keyboardAnimationVSyncClient;
1601
1649
1602
1650
[UIView animateWithDuration: duration
@@ -1639,45 +1687,28 @@ - (void)setupKeyboardSpringAnimationIfNeeded:(CAAnimation*)keyboardAnimation {
1639
1687
toValue: self .targetViewInsetBottom]);
1640
1688
}
1641
1689
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
+ }
1676
1695
NSAssert (_keyboardAnimationVSyncClient == nil ,
1677
1696
@" _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];
1681
1712
_keyboardAnimationVSyncClient.allowPauseAfterVsync = NO ;
1682
1713
[_keyboardAnimationVSyncClient await ];
1683
1714
}
0 commit comments