Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
8472d6d
first keyboard commit
CoolDude53 Nov 14, 2022
c6dab59
first keyboard commit
CoolDude53 Nov 14, 2022
11bab51
Merge branch 'main' of github.com:CoolDude53/engine into ios-keyboard…
CoolDude53 Nov 14, 2022
6e64b0d
cleaned up from initial testing
CoolDude53 Nov 14, 2022
142a133
added keyboard animation stop calculation
CoolDude53 Nov 24, 2022
96c4c5d
added keyboard animation stop calculation
CoolDude53 Nov 24, 2022
eff2b16
Merge branch 'flutter:main' into ios-keyboard-animation
CoolDude53 Nov 24, 2022
cc31006
lucky updates :)
CoolDude53 Nov 24, 2022
b1f484e
Merge branch 'flutter:main' into ios-keyboard-animation
CoolDude53 Nov 24, 2022
ad15be4
type change
CoolDude53 Nov 24, 2022
3e1a279
Merge branch 'ios-keyboard-animation' of github.com:CoolDude53/engine…
CoolDude53 Nov 24, 2022
a5027d3
final touches
CoolDude53 Nov 27, 2022
84d7b8e
final touches
CoolDude53 Nov 27, 2022
1e208d1
final touches
CoolDude53 Nov 27, 2022
756ae31
Merge branch 'flutter:main' into ios-keyboard-animation
CoolDude53 Nov 27, 2022
2b3743e
removed KeyboardAnimationView class
CoolDude53 Dec 1, 2022
b38cad0
removed KeyboardAnimationView class
CoolDude53 Dec 1, 2022
489bd1d
Merge branch 'ios-keyboard-animation' of github.com:CoolDude53/engine…
CoolDude53 Dec 1, 2022
0aeccc9
dynamic keyboard spring curve implementation
CoolDude53 Dec 2, 2022
1cd784a
broke out spring curve to own objc files
CoolDude53 Dec 2, 2022
ef8481c
broke out spring curve to own objc files
CoolDude53 Dec 2, 2022
582f2e0
simplified and added test
CoolDude53 Dec 8, 2022
3179417
modified spring formula to use damping
CoolDude53 Dec 8, 2022
467e1ce
added logic for compounding simultaneous animation calls
CoolDude53 Dec 8, 2022
98ee432
Merge branch 'flutter:main' into ios-keyboard-animation
CoolDude53 Dec 8, 2022
7436731
remove unnecessary code
CoolDude53 Dec 8, 2022
ace0211
cleanup
CoolDude53 Dec 9, 2022
c285ad9
cleanup
CoolDude53 Dec 9, 2022
49abfc3
update springCurveIos file
CoolDude53 Dec 9, 2022
0fb7a03
Merge branch 'flutter:main' into ios-keyboard-animation
CoolDude53 Dec 12, 2022
3cc8638
cleaning up
CoolDude53 Dec 13, 2022
b6b8747
Merge branch 'flutter:main' into ios-keyboard-animation
CoolDude53 Dec 13, 2022
20ffdc9
simple optimizations
CoolDude53 Dec 13, 2022
1abe18d
comment update
CoolDude53 Dec 13, 2022
3e5ef3f
bool update
CoolDude53 Dec 13, 2022
7c335d5
Merge remote-tracking branch 'upstream/main' into ios-keyboard-animation
CoolDude53 Dec 16, 2022
d764770
Merge branch 'flutter:main' into ios-keyboard-animation
CoolDude53 Dec 16, 2022
328b166
credit spring calculation project
CoolDude53 Dec 16, 2022
99f5d15
improved setupKeyboardAnimationCureveIfNeeded tests
CoolDude53 Dec 21, 2022
03c1f75
Optimized compounding animation checks and added new tests
CoolDude53 Dec 21, 2022
c143f19
Merge branch 'flutter:main' into ios-keyboard-animation
CoolDude53 Dec 21, 2022
c03d642
changed viewport update logic
CoolDude53 Dec 22, 2022
fd2eaee
Update FlutterViewControllerTest.mm
CoolDude53 Jan 2, 2023
33ca106
Updated license
CoolDude53 Jan 2, 2023
934bcf8
Updated tests
CoolDude53 Jan 3, 2023
5f7d563
Merge branch 'flutter:main' into ios-keyboard-animation
CoolDude53 Jan 3, 2023
76245e7
Cleanup
CoolDude53 Jan 4, 2023
d5a506f
Merge branch 'flutter:main' into ios-keyboard-animation
CoolDude53 Jan 4, 2023
e70e1bc
Merge branch 'flutter:main' into ios-keyboard-animation
CoolDude53 Jan 4, 2023
73062e7
Migrated spring class based on React
CoolDude53 Jan 4, 2023
b2a92dd
Updated syntax
CoolDude53 Jan 4, 2023
61b70f6
Update shell/platform/darwin/ios/framework/Source/spring_curve_ios.mm
CoolDude53 Jan 4, 2023
059bb70
Update shell/platform/darwin/ios/framework/Source/spring_curve_ios.h
CoolDude53 Jan 4, 2023
9c78679
Updated naming
CoolDude53 Jan 4, 2023
ebcb722
Updated naming
CoolDude53 Jan 4, 2023
3728335
Optimized spring model calculations
CoolDude53 Jan 4, 2023
6d02512
Improved interpolation accuracy
CoolDude53 Jan 5, 2023
3530db3
Revert "Improved interpolation accuracy"
CoolDude53 Jan 5, 2023
fb497a4
Updated comment
CoolDude53 Jan 5, 2023
3dcb341
Updated spring curve comments
CoolDude53 Jan 5, 2023
bc22eef
Merge branch 'flutter:main' into ios-keyboard-animation
CoolDude53 Feb 2, 2023
b797c91
updated to work with third_party spring animation
CoolDude53 Feb 2, 2023
f4556a8
updated to use SpringAnimation to/from values
CoolDude53 Feb 2, 2023
b9d0d78
updated license (removed old files)
CoolDude53 Feb 3, 2023
f35a1e8
updates
CoolDude53 Feb 3, 2023
4ed2380
allow updating springanimation position values
CoolDude53 Feb 3, 2023
29b8ace
updated test
CoolDude53 Feb 3, 2023
13faeec
update
CoolDude53 Feb 3, 2023
4682d80
fixes
CoolDude53 Feb 3, 2023
bc298b3
Merge branch 'flutter:main' into ios-keyboard-animation
CoolDude53 Feb 6, 2023
2fe2cf6
Merge branch 'flutter:main' into ios-keyboard-animation
CoolDude53 Feb 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -4990,6 +4990,8 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_messa
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/profiler_metrics_ios.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/profiler_metrics_ios.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/spring_curve_ios.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/spring_curve_ios.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/module.modulemap
Expand Down
2 changes: 2 additions & 0 deletions shell/platform/darwin/ios/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ source_set("flutter_framework_source") {
"framework/Source/platform_message_response_darwin.mm",
"framework/Source/profiler_metrics_ios.h",
"framework/Source/profiler_metrics_ios.mm",
"framework/Source/spring_curve_ios.h",
"framework/Source/spring_curve_ios.mm",
"framework/Source/vsync_waiter_ios.h",
"framework/Source/vsync_waiter_ios.mm",
"ios_context.h",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.h"
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h"
#import "flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h"
#import "flutter/shell/platform/darwin/ios/framework/Source/spring_curve_ios.h"
#import "flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h"
#import "flutter/shell/platform/darwin/ios/platform_view_ios.h"
#import "flutter/shell/platform/embedder/embedder.h"
Expand Down Expand Up @@ -65,6 +66,10 @@ @interface FlutterViewController () <FlutterBinaryMessenger, UIScrollViewDelegat
*/
@property(nonatomic, assign) double targetViewInsetBottom;
@property(nonatomic, retain) VSyncClient* keyboardAnimationVSyncClient;
@property(nonatomic, assign) BOOL keyboardAnimationIsShowing;
@property(nonatomic, assign) BOOL keyboardAnimationIsCompounding;
@property(nonatomic, assign) fml::TimePoint keyboardAnimationStartTime;
@property(nonatomic, assign) CGFloat originalViewInsetBottom;
@property(nonatomic, assign) BOOL isKeyboardInOrTransitioningFromBackground;

/// VSyncClient for touch events delivery frame rate correction.
Expand Down Expand Up @@ -123,6 +128,7 @@ @implementation FlutterViewController {
// https://github.com/flutter/flutter/issues/35050
fml::scoped_nsobject<UIScrollView> _scrollView;
fml::scoped_nsobject<UIView> _keyboardAnimationView;
fml::scoped_nsobject<KeyboardSpringCurve> _keyboardSpringCurve;
MouseState _mouseState;
// Timestamp after which a scroll inertia cancel event should be inferred.
NSTimeInterval _scrollInertiaEventStartline;
Expand Down Expand Up @@ -594,6 +600,10 @@ - (UIView*)keyboardAnimationView {
return _keyboardAnimationView.get();
}

- (KeyboardSpringCurve*)keyboardSpringCurve {
return _keyboardSpringCurve.get();
}

- (UIScreen*)mainScreenIfViewLoaded {
if (@available(iOS 13.0, *)) {
if (self.viewIfLoaded == nil) {
Expand Down Expand Up @@ -1321,6 +1331,7 @@ - (void)handleKeyboardNotification:(NSNotification*)notification {
}

NSDictionary* info = notification.userInfo;
CGRect beginKeyboardFrame = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
CGRect keyboardFrame = [info[UIKeyboardFrameEndUserInfoKey] CGRectValue];
FlutterKeyboardMode keyboardMode = [self calculateKeyboardAttachMode:notification];
CGFloat calculatedInset = [self calculateKeyboardInset:keyboardFrame keyboardMode:keyboardMode];
Expand All @@ -1332,6 +1343,15 @@ - (void)handleKeyboardNotification:(NSNotification*)notification {

self.targetViewInsetBottom = calculatedInset;
NSTimeInterval duration = [info[UIKeyboardAnimationDurationUserInfoKey] doubleValue];

BOOL keyboardWillShow = beginKeyboardFrame.origin.y > keyboardFrame.origin.y;

// Flag for simultaneous compounding animation calls.
self.keyboardAnimationIsCompounding = self.keyboardAnimationIsShowing == keyboardWillShow;

// Mark keyboard as showing or hiding.
self.keyboardAnimationIsShowing = keyboardWillShow;

[self startKeyBoardAnimation:duration];
}

Expand Down Expand Up @@ -1509,14 +1529,20 @@ - (void)startKeyBoardAnimation:(NSTimeInterval)duration {

if ([self keyboardAnimationView].superview == nil) {
[self.view addSubview:[self keyboardAnimationView]];
} else if (self.keyboardAnimationIsCompounding) {
// If keyboardAnimationView has superview, means current animation is running,
// and if keyboard animation is in the same direction as current animation, ignore it.
return;
}

// Remove running animation when start another animation.
[[self keyboardAnimationView].layer removeAllAnimations];

// Set animation begin value.
// Set animation begin value and DisplayLink tracking values.
[self keyboardAnimationView].frame =
CGRectMake(0, _viewportMetrics.physical_view_inset_bottom, 0, 0);
self.keyboardAnimationStartTime = fml::TimePoint().Now();
self.originalViewInsetBottom = _viewportMetrics.physical_view_inset_bottom;

// Invalidate old vsync client if old animation is not completed.
[self invalidateKeyboardAnimationVSyncClient];
Expand All @@ -1527,6 +1553,11 @@ - (void)startKeyBoardAnimation:(NSTimeInterval)duration {
animations:^{
// Set end value.
[self keyboardAnimationView].frame = CGRectMake(0, self.targetViewInsetBottom, 0, 0);

// Setup keyboard animation interpolation.
CAAnimation* keyboardAnimation =
[[self keyboardAnimationView].layer animationForKey:@"position"];
[self setupKeyboardAnimationCurveIfNeeded:keyboardAnimation];
}
completion:^(BOOL finished) {
if (_keyboardAnimationVSyncClient == currentVsyncClient) {
Expand All @@ -1540,6 +1571,21 @@ - (void)startKeyBoardAnimation:(NSTimeInterval)duration {
}];
}

- (void)setupKeyboardAnimationCurveIfNeeded:(CAAnimation*)keyboardAnimation {
// Set keyboard spring animation details (if animation is CASpringAnimation).
if ([keyboardAnimation isKindOfClass:[CASpringAnimation class]]) {
CASpringAnimation* keyboardSpringAnimation = (CASpringAnimation*)keyboardAnimation;
_keyboardSpringCurve.reset([[KeyboardSpringCurve alloc]
initWithStiffness:keyboardSpringAnimation.stiffness
damping:keyboardSpringAnimation.damping
mass:keyboardSpringAnimation.mass
initialVelocity:keyboardSpringAnimation.initialVelocity]);
} else {
// Reset to use fallback keyboard animation tracking.
_keyboardSpringCurve.reset();
}
}

- (void)setupKeyboardAnimationVsyncClient {
auto callback = [weakSelf =
[self getWeakPtr]](std::unique_ptr<flutter::FrameTimingsRecorder> recorder) {
Expand All @@ -1556,12 +1602,23 @@ - (void)setupKeyboardAnimationVsyncClient {
// Ensure the keyboardAnimationView is in view hierarchy when animation running.
[flutterViewController.get().view addSubview:[flutterViewController keyboardAnimationView]];
}
if ([flutterViewController keyboardAnimationView].layer.presentationLayer) {
CGFloat value =
[flutterViewController keyboardAnimationView].layer.presentationLayer.frame.origin.y;
flutterViewController.get()->_viewportMetrics.physical_view_inset_bottom = value;
[flutterViewController updateViewportMetrics];

CGFloat newY;
if ([flutterViewController keyboardSpringCurve] == nil) {
newY =
flutterViewController.get().keyboardAnimationView.layer.presentationLayer.frame.origin.y;
} else {
double start = flutterViewController.get().originalViewInsetBottom;
double end = flutterViewController.get().targetViewInsetBottom;
fml::TimeDelta timeElapsed = recorder.get()->GetVsyncTargetTime() -
flutterViewController.get().keyboardAnimationStartTime;
double keyboardAnimationStop =
[[flutterViewController keyboardSpringCurve] curveFunc:timeElapsed.ToSecondsF()];
newY = start + (end - start) * keyboardAnimationStop;
}

flutterViewController.get()->_viewportMetrics.physical_view_inset_bottom = newY;
[flutterViewController updateViewportMetrics];
};
flutter::Shell& shell = [_engine.get() shell];
NSAssert(_keyboardAnimationVSyncClient == nil,
Expand Down Expand Up @@ -1913,8 +1970,8 @@ - (BOOL)isAlwaysUse24HourFormat {
}

// The brightness mode of the platform, e.g., light or dark, expressed as a string that
// is understood by the Flutter framework. See the settings system channel for more
// information.
// is understood by the Flutter framework. See the settings
// system channel for more information.
- (NSString*)brightnessMode {
if (@available(iOS 13, *)) {
UIUserInterfaceStyle style = self.traitCollection.userInterfaceStyle;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ - (FlutterKeyboardMode)calculateKeyboardAttachMode:(NSNotification*)notification
- (CGFloat)calculateMultitaskingAdjustment:(CGRect)screenRect keyboardFrame:(CGRect)keyboardFrame;
- (void)startKeyBoardAnimation:(NSTimeInterval)duration;
- (void)setupKeyboardAnimationVsyncClient;
- (UIView*)keyboardAnimationView;
- (void)setupKeyboardAnimationCurveIfNeeded:(CAAnimation*)keyboardAnimation;
- (void)ensureViewportMetricsIsCorrect;
- (void)invalidateKeyboardAnimationVSyncClient;
- (void)addInternalPlugins;
Expand Down Expand Up @@ -190,6 +192,22 @@ - (void)testStartKeyboardAnimationWillInvokeSetupKeyboardAnimationVsyncClient {
OCMVerify([viewControllerMock setupKeyboardAnimationVsyncClient]);
}

- (void)testStartKeyboardAnimationWillInvokeSetupKeyboardAnimationCurveIfNeeded {
FlutterEngine* engine = [[FlutterEngine alloc] init];
[engine runWithEntrypoint:nil];
FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engine
nibName:nil
bundle:nil];
FlutterViewController* viewControllerMock = OCMPartialMock(viewController);
viewControllerMock.targetViewInsetBottom = 100;
[viewControllerMock startKeyBoardAnimation:0.25];

CAAnimation* keyboardAnimation =
[[viewControllerMock keyboardAnimationView].layer animationForKey:@"position"];

OCMVerify([viewControllerMock setupKeyboardAnimationCurveIfNeeded:keyboardAnimation]);
}

- (void)testShouldIgnoreKeyboardNotification {
FlutterEngine* mockEngine = OCMPartialMock([[FlutterEngine alloc] init]);
[mockEngine createShell:@"" libraryURI:@"" initialRoute:nil];
Expand Down
24 changes: 24 additions & 0 deletions shell/platform/darwin/ios/framework/Source/spring_curve_ios.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_SPRING_CURVE_IOS_H_
#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_SPRING_CURVE_IOS_H_

#include <Foundation/NSObject.h>

@interface KeyboardSpringCurve : NSObject

- (instancetype)initWithStiffness:(double)stiffness
damping:(double)damping
mass:(double)mass
initialVelocity:(double)initialVelocity;

- (double)curveFunc:(double)t;

@property(nonatomic, assign) double initialVelocity;
@property(nonatomic, assign) double dampingRatio;
@property(nonatomic, assign) double omega;
@end

#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_SPRING_CURVE_IOS_H_
53 changes: 53 additions & 0 deletions shell/platform/darwin/ios/framework/Source/spring_curve_ios.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "flutter/shell/platform/darwin/ios/framework/Source/spring_curve_ios.h"

#include <Foundation/Foundation.h>

// Spring calculation adapted from Pan Yusheng's research project.
// See: https://github.com/CosynPa/RevealSpringAnimation.
@implementation KeyboardSpringCurve
- (instancetype)initWithStiffness:(double)stiffness
damping:(double)damping
mass:(double)mass
initialVelocity:(double)initialVelocity {
self = [super init];
if (self) {
_dampingRatio = MIN(1.0, damping / 2 / sqrt(stiffness * mass));
_initialVelocity = initialVelocity;

double response = MAX(1e-5, 2 * M_PI / sqrt(stiffness / mass));
_omega = 2 * M_PI / response;
}
return self;
}

- (double)curveFunc:(double)t {
double v0 = self.initialVelocity;
double zeta = self.dampingRatio;

double y;
if (abs(zeta - 1.0) < 1e-8) {
double c1 = -1.0;
double c2 = v0 - self.omega;
y = (c1 + c2 * t) * exp(-self.omega * t);
} else if (zeta > 1) {
double s1 = self.omega * (-zeta + sqrt(zeta * zeta - 1));
double s2 = self.omega * (-zeta - sqrt(zeta * zeta - 1));
double c1 = (-s2 - v0) / (s2 - s1);
double c2 = (s1 + v0) / (s2 - s1);
y = c1 * exp(s1 * t) + c2 * exp(s2 * t);
} else {
double a = -self.omega * zeta;
double b = self.omega * sqrt(1 - zeta * zeta);
double c2 = (v0 + a) / b;
double theta = atan(c2);
// Alternatively y = (-cos(b * t) + c2 * sin(b * t)) * exp(a * t)
y = sqrt(1 + c2 * c2) * exp(a * t) * cos(b * t + theta + M_PI);
}

return y + 1;
}
@end