-
Notifications
You must be signed in to change notification settings - Fork 6k
[iOS] Avoid jitter and laggy when user is dragging on iOS Promotion devices #35592
Changes from 1 commit
1b1b2d7
b655406
8e93dae
85bc1b5
ba09d7c
59000d6
47abf4e
c6b77a9
4bf7f3f
8fceea1
2cd6988
2bc5880
72b3ff7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -65,6 +65,9 @@ @interface FlutterViewController () <FlutterBinaryMessenger, UIScrollViewDelegat | |
| @property(nonatomic, assign) double targetViewInsetBottom; | ||
| @property(nonatomic, retain) VSyncClient* keyboardAnimationVSyncClient; | ||
|
|
||
| /// VSyncClient for touch callback's rate correction. | ||
| @property(nonatomic, retain) VSyncClient* touchRateCorrectionVSyncClient; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is VSyncClient necessary here? Since this is just for increasing resolution of touch events and doesn't directly affect rendering, should we just use CADisplayLink directly?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using VSyncClient ensures the preferred frame rate that used is the same as the one used on UIThread. |
||
|
|
||
| /* | ||
| * Mouse and trackpad gesture recognizers | ||
| */ | ||
|
|
@@ -671,6 +674,9 @@ - (void)viewDidLoad { | |
| // Register internal plugins. | ||
| [self addInternalPlugins]; | ||
|
|
||
| // Setup vsync client to correct touch rate. | ||
| [self setupTouchRateCorrectionVSyncClient]; | ||
|
|
||
| if (@available(iOS 13.4, *)) { | ||
| _hoverGestureRecognizer = | ||
| [[UIHoverGestureRecognizer alloc] initWithTarget:self action:@selector(hoverEvent:)]; | ||
|
|
@@ -833,6 +839,7 @@ - (void)dealloc { | |
| [self deregisterNotifications]; | ||
|
|
||
| [self invalidateKeyboardAnimationVSyncClient]; | ||
| [self invalidateTouchRateCorrectionVSyncClient]; | ||
| _scrollView.get().delegate = nil; | ||
| _hoverGestureRecognizer.delegate = nil; | ||
| [_hoverGestureRecognizer release]; | ||
|
|
@@ -966,6 +973,9 @@ - (void)dispatchTouches:(NSSet*)touches | |
| } | ||
| } | ||
|
|
||
| // Activate or pause touch rate correction according to the touches when user is interacting. | ||
|
||
| [self triggerTouchRateCorrectionIfNeeded:touches]; | ||
|
|
||
| const CGFloat scale = [UIScreen mainScreen].scale; | ||
| auto packet = | ||
| std::make_unique<flutter::PointerDataPacket>(touches.count + touches_to_remove_count); | ||
|
|
@@ -1111,6 +1121,53 @@ - (void)forceTouchesCancelled:(NSSet*)touches { | |
| [self dispatchTouches:touches pointerDataChangeOverride:&cancel event:nullptr]; | ||
| } | ||
|
|
||
| #pragma mark - Touch events rate correction | ||
|
|
||
| - (void)setupTouchRateCorrectionVSyncClient { | ||
| NSAssert(_touchRateCorrectionVSyncClient == nil, | ||
luckysmg marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| @"_touchRateCorrectionVSyncClient should be nil when setup"); | ||
| double displayRefreshRate = [DisplayLinkManager displayRefreshRate]; | ||
| if (displayRefreshRate <= 60) { | ||
luckysmg marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // If current device's max frame rate is not larger than 60HZ, the delivery rate of touch events | ||
| // is the same with render vsync rate. So we don't need to create | ||
|
||
| // _touchRateCorrectionVSyncClient to correct touch callback's rate. | ||
| return; | ||
| } | ||
|
|
||
| flutter::Shell& shell = [_engine.get() shell]; | ||
| auto callback = [](std::unique_ptr<flutter::FrameTimingsRecorder> recorder) { | ||
| // Do nothing in this block. Just trigger system to callback touch events with correct rate. | ||
| }; | ||
| _touchRateCorrectionVSyncClient = | ||
| [[VSyncClient alloc] initWithTaskRunner:shell.GetTaskRunners().GetPlatformTaskRunner() | ||
| callback:callback]; | ||
| _touchRateCorrectionVSyncClient.allowPauseAfterVsync = NO; | ||
| } | ||
|
|
||
| - (void)triggerTouchRateCorrectionIfNeeded:(NSSet*)touches { | ||
| // As long as there is a touch's phase is UITouchPhaseBegan or UITouchPhaseMoved, | ||
| // we should activate the correction. Otherwise we will pause the correction. | ||
|
||
| BOOL isUserInteracting = NO; | ||
| for (UITouch* touch in touches) { | ||
| if (touch.phase == UITouchPhaseBegan || touch.phase == UITouchPhaseMoved) { | ||
| isUserInteracting = YES; | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| if (isUserInteracting && [_engine.get() viewController] == self) { | ||
| [_touchRateCorrectionVSyncClient await]; | ||
| } else { | ||
| [_touchRateCorrectionVSyncClient pause]; | ||
| } | ||
| } | ||
|
|
||
| - (void)invalidateTouchRateCorrectionVSyncClient { | ||
| [_touchRateCorrectionVSyncClient invalidate]; | ||
| [_touchRateCorrectionVSyncClient release]; | ||
| _touchRateCorrectionVSyncClient = nil; | ||
| } | ||
|
|
||
| #pragma mark - Handle view resizing | ||
|
|
||
| - (void)updateViewportMetrics { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -45,6 +45,8 @@ | |
|
|
||
| - (void)await; | ||
|
|
||
| - (void)pause; | ||
|
|
||
| - (void)invalidate; | ||
|
|
||
| - (double)getRefreshRate; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nits:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe also add a short explanation about why this is needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.