Skip to content

Commit bca3452

Browse files
authored
feat(ios): improved handling for navigation events (#10757)
1 parent 1ef4730 commit bca3452

File tree

9 files changed

+121
-159
lines changed

9 files changed

+121
-159
lines changed

apps/automated/src/ui/tab-view/tab-view-root-tests.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,16 +140,11 @@ export function test_offset_zero_should_raise_same_events() {
140140
resetActualEventsRaised();
141141
waitUntilNavigatedToMaxTimeout([items[2].page], () => (tabView.selectedIndex = 2));
142142

143-
const startEvents = ['Tab0 Frame0 Page0 unloaded', 'Tab0 Frame0 unloaded'];
144-
if (__APPLE__) {
145-
startEvents.push('Tab0 Frame0 Page0 navigatingFrom');
146-
}
147-
const expectedEventsRaisedAfterSelectThirdTab = [startEvents, [], ['Tab2 Frame2 loaded', 'Tab2 Frame2 Page2 navigatingTo', 'Tab2 Frame2 Page2 loaded', 'Tab2 Frame2 Page2 navigatedTo']];
143+
const expectedEventsRaisedAfterSelectThirdTab = [['Tab0 Frame0 Page0 unloaded', 'Tab0 Frame0 unloaded'], [], ['Tab2 Frame2 loaded', 'Tab2 Frame2 Page2 navigatingTo', 'Tab2 Frame2 Page2 loaded', 'Tab2 Frame2 Page2 navigatedTo']];
148144

149145
TKUnit.assertDeepEqual(actualEventsRaised, expectedEventsRaisedAfterSelectThirdTab);
150146

151147
resetActualEventsRaised();
152-
153148
waitUntilTabViewReady(items[0].page, () => (tabView.selectedIndex = 0));
154149

155150
const expectedEventsRaisedAfterReturnToFirstTab = [['Tab0 Frame0 Page0 loaded', 'Tab0 Frame0 loaded'], [], ['Tab2 Frame2 Page2 unloaded', 'Tab2 Frame2 unloaded']];

packages/core/ui/frame/frame-common.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Page } from '../page';
44
import { View, CustomLayoutView, CSSType } from '../core/view';
55
import { Property } from '../core/properties';
66
import { Trace } from '../../trace';
7-
import { frameStack, topmost as frameStackTopmost, _pushInFrameStack, _popFromFrameStack, _removeFromFrameStack } from './frame-stack';
7+
import { frameStack, topmost as frameStackTopmost, _pushInFrameStack, _popFromFrameStack, _removeFromFrameStack, _isFrameStackEmpty } from './frame-stack';
88
import { viewMatchesModuleContext } from '../core/view/view-common';
99
import { getAncestor } from '../core/view-base';
1010
import { Builder } from '../builder';
@@ -542,6 +542,10 @@ export class FrameBase extends CustomLayoutView {
542542
}
543543
}
544544

545+
public _isFrameStackEmpty() {
546+
return _isFrameStackEmpty();
547+
}
548+
545549
public _pushInFrameStack() {
546550
_pushInFrameStack(this);
547551
}

packages/core/ui/frame/frame-interfaces.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ export interface NavigationEntry extends ViewEntry {
3636
}
3737

3838
export interface NavigationContext {
39-
entry: BackstackEntry;
40-
// TODO: remove isBackNavigation for NativeScript 7.0
39+
entry?: BackstackEntry;
40+
/**
41+
* @deprecated Use navigationType instead.
42+
*/
4143
isBackNavigation: boolean;
4244
navigationType: NavigationType;
4345
}

packages/core/ui/frame/frame-stack.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ export function topmost(): FrameBase {
1111
return undefined;
1212
}
1313

14+
export function _isFrameStackEmpty(): boolean {
15+
return frameStack.length === 0;
16+
}
17+
1418
export function _pushInFrameStack(frame: FrameBase): void {
1519
if (frame._isInFrameStack && frameStack[frameStack.length - 1] === frame) {
1620
return;

packages/core/ui/frame/index.d.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,10 @@ export class Frame extends FrameBase {
258258
* @private
259259
*/
260260
_updateBackstack(entry: BackstackEntry, navigationType: NavigationType): void;
261+
/**
262+
* @private
263+
*/
264+
_isFrameStackEmpty(): boolean;
261265
/**
262266
* @private
263267
*/
@@ -404,7 +408,10 @@ export interface NavigationEntry extends ViewEntry {
404408
* Represents a context passed to navigation methods.
405409
*/
406410
export interface NavigationContext {
407-
entry: BackstackEntry;
411+
entry?: BackstackEntry;
412+
/**
413+
* @deprecated Use navigationType instead.
414+
*/
408415
isBackNavigation: boolean;
409416
navigationType: NavigationType;
410417
}

packages/core/ui/frame/index.ios.ts

Lines changed: 28 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { IOSHelper } from '../core/view/view-helper';
77
import { profile } from '../../profiling';
88
import { CORE_ANIMATION_DEFAULTS, ios as iOSUtils, layout } from '../../utils';
99
import { Trace } from '../../trace';
10-
import type { PageTransition } from '../transition/page-transition';
1110
import { SlideTransition } from '../transition/slide-transition';
1211
import { FadeTransition } from '../transition/fade-transition';
1312
import { SharedTransition } from '../transition/shared-transition';
@@ -22,11 +21,11 @@ const NAV_DEPTH = '_navDepth';
2221
const TRANSITION = '_transition';
2322
const NON_ANIMATED_TRANSITION = 'non-animated';
2423

25-
let navDepth = -1;
24+
let navDepth: number = -1;
25+
let navControllerDelegate: UINavigationControllerDelegate = null;
2626

2727
export class Frame extends FrameBase {
2828
viewController: UINavigationControllerImpl;
29-
_animatedDelegate: UINavigationControllerDelegate;
3029
public _ios: iOSFrame;
3130
iosNavigationBarClass: typeof NSObject;
3231
iosToolbarClass: typeof NSObject;
@@ -38,6 +37,11 @@ export class Frame extends FrameBase {
3837
}
3938

4039
createNativeView() {
40+
// Push frame back in frame stack since it was removed in disposeNativeView() method.
41+
if (this._currentEntry) {
42+
this._pushInFrameStack();
43+
}
44+
4145
return this.viewController.view;
4246
}
4347

@@ -61,7 +65,12 @@ export class Frame extends FrameBase {
6165

6266
this._removeFromFrameStack();
6367
this.viewController = null;
64-
this._animatedDelegate = null;
68+
69+
// This was the last frame so we can get rid of the controller delegate reference
70+
if (this._isFrameStackEmpty()) {
71+
navControllerDelegate = null;
72+
}
73+
6574
if (this._ios) {
6675
this._ios.controller = null;
6776
this._ios = null;
@@ -120,11 +129,12 @@ export class Frame extends FrameBase {
120129

121130
const nativeTransition = _getNativeTransition(navigationTransition, true);
122131
if (!nativeTransition && navigationTransition) {
123-
if (!this._animatedDelegate) {
124-
this._animatedDelegate = <UINavigationControllerDelegate>UINavigationControllerAnimatedDelegate.initWithOwner(new WeakRef(this));
132+
if (!navControllerDelegate) {
133+
navControllerDelegate = <UINavigationControllerDelegate>UINavigationControllerAnimatedDelegate.new();
125134
}
126-
this._ios.controller.delegate = this._animatedDelegate;
127-
viewController[DELEGATE] = this._animatedDelegate;
135+
136+
this._ios.controller.delegate = navControllerDelegate;
137+
viewController[DELEGATE] = navControllerDelegate;
128138
if (navigationTransition.instance) {
129139
this.transitionId = navigationTransition.instance.id;
130140
const transitionState = SharedTransition.getState(this.transitionId);
@@ -346,19 +356,6 @@ export class Frame extends FrameBase {
346356
public _setNativeViewFrame(nativeView: UIView, frame: CGRect) {
347357
//
348358
}
349-
350-
public _onNavigatingTo(backstackEntry: BackstackEntry, isBack: boolean) {
351-
// for now to not break iOS events chain (calling navigation events from controller delegates)
352-
// we dont call super(which would also trigger events) but only notify the frame of the navigation
353-
// though it means events are not triggered at the same time (lifecycle) on iOS / Android
354-
this.notify({
355-
eventName: Page.navigatingToEvent,
356-
object: this,
357-
isBack,
358-
entry: backstackEntry,
359-
fromEntry: this._currentEntry,
360-
});
361-
}
362359
}
363360

364361
const transitionDelegates = new Array<TransitionDelegate>();
@@ -413,14 +410,6 @@ class TransitionDelegate extends NSObject {
413410
@NativeClass
414411
class UINavigationControllerAnimatedDelegate extends NSObject implements UINavigationControllerDelegate {
415412
public static ObjCProtocols = [UINavigationControllerDelegate];
416-
owner: WeakRef<Frame>;
417-
transition: PageTransition;
418-
419-
static initWithOwner(owner: WeakRef<Frame>) {
420-
const delegate = <UINavigationControllerAnimatedDelegate>UINavigationControllerAnimatedDelegate.new();
421-
delegate.owner = owner;
422-
return delegate;
423-
}
424413

425414
navigationControllerAnimationControllerForOperationFromViewControllerToViewController(navigationController: UINavigationController, operation: number, fromVC: UIViewController, toVC: UIViewController): UIViewControllerAnimatedTransitioning {
426415
let viewController: UIViewController;
@@ -445,29 +434,30 @@ class UINavigationControllerAnimatedDelegate extends NSObject implements UINavig
445434
if (Trace.isEnabled()) {
446435
Trace.write(`UINavigationControllerImpl.navigationControllerAnimationControllerForOperationFromViewControllerToViewController(${operation}, ${fromVC}, ${toVC}), transition: ${JSON.stringify(navigationTransition)}`, Trace.categories.NativeLifecycle);
447436
}
448-
this.transition = navigationTransition.instance;
449437

450-
if (!this.transition) {
438+
let transition = navigationTransition.instance;
439+
440+
if (!transition) {
451441
if (navigationTransition.name) {
452442
const curve = _getNativeCurve(navigationTransition);
453443
const name = navigationTransition.name.toLowerCase();
454444
if (name.indexOf('slide') === 0) {
455-
const direction = name.substring('slide'.length) || 'left'; //Extract the direction from the string
456-
this.transition = new SlideTransition(direction, navigationTransition.duration, curve);
445+
const direction = name.substring('slide'.length) || 'left'; // Extract the direction from the string
446+
transition = new SlideTransition(direction, navigationTransition.duration, curve);
457447
} else if (name === 'fade') {
458-
this.transition = new FadeTransition(navigationTransition.duration, curve);
448+
transition = new FadeTransition(navigationTransition.duration, curve);
459449
}
460450
}
461451
}
462452

463-
if (this.transition?.iosNavigatedController) {
464-
return this.transition.iosNavigatedController(navigationController, operation, fromVC, toVC);
453+
if (transition?.iosNavigatedController) {
454+
return transition.iosNavigatedController(navigationController, operation, fromVC, toVC);
465455
}
466456
return null;
467457
}
468458

469-
navigationControllerInteractionControllerForAnimationController(navigationController: UINavigationController, animationController: UIViewControllerAnimatedTransitioning): UIViewControllerInteractiveTransitioning {
470-
const owner = this.owner?.deref();
459+
navigationControllerInteractionControllerForAnimationController(navigationController: UINavigationControllerImpl, animationController: UIViewControllerAnimatedTransitioning): UIViewControllerInteractiveTransitioning {
460+
const owner = navigationController.owner;
471461
if (owner) {
472462
const state = SharedTransition.getState(owner.transitionId);
473463
if (state?.instance?.iosInteractionDismiss) {

packages/core/ui/gestures/index.ios.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class UIGestureRecognizerDelegateImpl extends NSObject implements UIGestureRecog
3737
return false;
3838
}
3939
}
40-
const recognizerDelegateInstance: UIGestureRecognizerDelegateImpl = <UIGestureRecognizerDelegateImpl>UIGestureRecognizerDelegateImpl.new();
40+
const recognizerDelegateInstance = <UIGestureRecognizerDelegateImpl>UIGestureRecognizerDelegateImpl.new();
4141

4242
@NativeClass
4343
class UIGestureRecognizerImpl extends NSObject {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy