Skip to content

Commit 8fea9e5

Browse files
authored
fix(ios): allow creating missing view controllers on reused views (#10941)
1 parent e434373 commit 8fea9e5

File tree

3 files changed

+70
-30
lines changed

3 files changed

+70
-30
lines changed

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@ let navControllerDelegate: UINavigationControllerDelegate = null;
2828

2929
export class Frame extends FrameBase {
3030
viewController: UINavigationControllerImpl;
31-
public _ios: iOSFrame;
3231
iosNavigationBarClass: typeof NSObject;
3332
iosToolbarClass: typeof NSObject;
3433

34+
private _ios: iOSFrame;
35+
3536
constructor() {
3637
super();
3738
this._ios = new iOSFrame(this);
@@ -44,7 +45,13 @@ export class Frame extends FrameBase {
4445
this._pushInFrameStack();
4546
}
4647

47-
return this.viewController.view;
48+
// View controller can be disposed during view disposal, so make sure to create a new one if not defined
49+
if (!this._ios) {
50+
this._ios = new iOSFrame(this);
51+
this.viewController = this._ios.controller;
52+
}
53+
54+
return this._ios.controller.view;
4855
}
4956

5057
public disposeNativeView() {
@@ -755,9 +762,7 @@ export function _getNativeCurve(transition: NavigationTransition): UIViewAnimati
755762
return UIViewAnimationCurve.EaseInOut;
756763
}
757764

758-
/* tslint:disable */
759765
class iOSFrame implements iOSFrameDefinition {
760-
/* tslint:enable */
761766
private _controller: UINavigationControllerImpl;
762767
private _showNavigationBar: boolean;
763768
private _navBarVisibility: 'auto' | 'never' | 'always' = 'auto';

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,13 @@ export class Page extends PageBase {
386386
}
387387

388388
createNativeView() {
389-
return this.viewController.view;
389+
// View controller can be disposed during view disposal, so make sure to create a new one if not defined
390+
if (!this._ios) {
391+
const controller = UIViewControllerImpl.initWithOwner(new WeakRef(this));
392+
controller.view.backgroundColor = this._backgroundColor;
393+
this.viewController = this._ios = controller;
394+
}
395+
return this._ios.view;
390396
}
391397

392398
disposeNativeView() {
@@ -447,7 +453,7 @@ export class Page extends PageBase {
447453

448454
public _updateStatusBarStyle(value?: string) {
449455
const frame = this.frame;
450-
if (frame && value) {
456+
if (frame?.ios && value) {
451457
const navigationController: UINavigationController = frame.ios.controller;
452458
const navigationBar = navigationController.navigationBar;
453459

@@ -497,7 +503,7 @@ export class Page extends PageBase {
497503

498504
const insets = this.getSafeAreaInsets();
499505

500-
if (!__VISIONOS__ && SDK_VERSION <= 10) {
506+
if (!__VISIONOS__ && SDK_VERSION <= 10 && this.viewController) {
501507
// iOS 10 and below don't have safe area insets API,
502508
// there we need only the top inset on the Page
503509
insets.top = layout.round(layout.toDevicePixels(this.viewController.view.safeAreaLayoutGuide.layoutFrame.origin.y));

packages/core/ui/tab-view/index.ios.ts

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,7 @@ class UITabBarControllerDelegateImpl extends NSObject implements UITabBarControl
117117
const owner = this._owner?.deref();
118118
if (owner) {
119119
// "< More" cannot be visible after clicking on the main tab bar buttons.
120-
const backToMoreWillBeVisible = false;
121-
owner._handleTwoNavigationBars(backToMoreWillBeVisible);
120+
owner._handleTwoNavigationBars(false);
122121
}
123122

124123
if (tabBarController.selectedViewController === viewController) {
@@ -135,7 +134,7 @@ class UITabBarControllerDelegateImpl extends NSObject implements UITabBarControl
135134

136135
const owner = this._owner?.deref();
137136
if (owner) {
138-
owner._onViewControllerShown(viewController);
137+
owner._onViewControllerShown(tabBarController, viewController);
139138
}
140139
}
141140
}
@@ -162,7 +161,7 @@ class UINavigationControllerDelegateImpl extends NSObject implements UINavigatio
162161
if (owner) {
163162
// If viewController is one of our tab item controllers, then "< More" will be visible shortly.
164163
// Otherwise viewController is the UIMoreListController which shows the list of all tabs beyond the 4th tab.
165-
const backToMoreWillBeVisible = owner._ios.viewControllers.containsObject(viewController);
164+
const backToMoreWillBeVisible = navigationController.tabBarController?.viewControllers?.containsObject(viewController);
166165
owner._handleTwoNavigationBars(backToMoreWillBeVisible);
167166
}
168167
}
@@ -175,7 +174,7 @@ class UINavigationControllerDelegateImpl extends NSObject implements UINavigatio
175174
navigationController.navigationBar.topItem.rightBarButtonItem = null;
176175
const owner = this._owner?.deref();
177176
if (owner) {
178-
owner._onViewControllerShown(viewController);
177+
owner._onViewControllerShown(navigationController.tabBarController, viewController);
179178
}
180179
}
181180
}
@@ -282,16 +281,24 @@ export class TabViewItem extends TabViewItemBase {
282281
export class TabView extends TabViewBase {
283282
public viewController: UITabBarControllerImpl;
284283
public items: TabViewItem[];
285-
public _ios: UITabBarControllerImpl;
284+
286285
private _delegate: UITabBarControllerDelegateImpl;
287286
private _moreNavigationControllerDelegate: UINavigationControllerDelegateImpl;
288287
private _iconsCache = {};
288+
private _ios: UITabBarControllerImpl;
289+
private _actionBarHiddenByTabView: boolean;
289290

290291
constructor() {
291292
super();
292-
293293
this.viewController = this._ios = UITabBarControllerImpl.initWithOwner(new WeakRef(this));
294-
this.nativeViewProtected = this._ios.view;
294+
}
295+
296+
createNativeView() {
297+
// View controller can be disposed during view disposal, so make sure to create a new one if not defined
298+
if (!this._ios) {
299+
this.viewController = this._ios = UITabBarControllerImpl.initWithOwner(new WeakRef(this));
300+
}
301+
return this._ios.view;
295302
}
296303

297304
initNativeView() {
@@ -303,6 +310,8 @@ export class TabView extends TabViewBase {
303310
disposeNativeView() {
304311
this._delegate = null;
305312
this._moreNavigationControllerDelegate = null;
313+
this.viewController = null;
314+
this._ios = null;
306315
super.disposeNativeView();
307316
}
308317

@@ -316,12 +325,19 @@ export class TabView extends TabViewBase {
316325
selectedView._pushInFrameStackRecursive();
317326
}
318327

319-
this._ios.delegate = this._delegate;
328+
if (this._ios) {
329+
this._ios.delegate = this._delegate;
330+
}
320331
}
321332

322333
public onUnloaded() {
323-
this._ios.delegate = null;
324-
this._ios.moreNavigationController.delegate = null;
334+
if (this._ios) {
335+
this._ios.delegate = null;
336+
337+
if (this._ios.moreNavigationController) {
338+
this._ios.moreNavigationController.delegate = null;
339+
}
340+
}
325341
super.onUnloaded();
326342
}
327343

@@ -375,38 +391,47 @@ export class TabView extends TabViewBase {
375391
this.setMeasuredDimension(widthAndState, heightAndState);
376392
}
377393

378-
public _onViewControllerShown(viewController: UIViewController) {
394+
public _onViewControllerShown(tabBarController: UITabBarController, viewController: UIViewController) {
379395
// This method could be called with the moreNavigationController or its list controller, so we have to check.
380396
if (Trace.isEnabled()) {
381397
Trace.write('TabView._onViewControllerShown(' + viewController + ');', Trace.categories.Debug);
382398
}
383-
if (this._ios.viewControllers && this._ios.viewControllers.containsObject(viewController)) {
384-
this.selectedIndex = this._ios.viewControllers.indexOfObject(viewController);
399+
if (tabBarController?.viewControllers && tabBarController.viewControllers.containsObject(viewController)) {
400+
this.selectedIndex = tabBarController.viewControllers.indexOfObject(viewController);
385401
} else {
386402
if (Trace.isEnabled()) {
387403
Trace.write('TabView._onViewControllerShown: viewController is not one of our viewControllers', Trace.categories.Debug);
388404
}
389405
}
390406
}
391407

392-
private _actionBarHiddenByTabView: boolean;
393408
public _handleTwoNavigationBars(backToMoreWillBeVisible: boolean) {
394409
if (Trace.isEnabled()) {
395410
Trace.write(`TabView._handleTwoNavigationBars(backToMoreWillBeVisible: ${backToMoreWillBeVisible})`, Trace.categories.Debug);
396411
}
397412

398413
// The "< Back" and "< More" navigation bars should not be visible simultaneously.
399-
const page = this.page || this._selectedView?.page || (<any>this)._selectedView?.currentPage;
414+
let page = this.page || this._selectedView?.page;
415+
416+
if (!page && this._selectedView instanceof Frame) {
417+
page = this._selectedView.currentPage;
418+
}
419+
400420
if (!page || !page.frame) {
401421
return;
402422
}
403423

404424
const actionBarVisible = page.frame._getNavBarVisible(page);
405425

406426
if (backToMoreWillBeVisible && actionBarVisible) {
407-
page.frame.ios._disableNavBarAnimation = true;
408-
page.actionBarHidden = true;
409-
page.frame.ios._disableNavBarAnimation = false;
427+
if (page.frame.ios) {
428+
page.frame.ios._disableNavBarAnimation = true;
429+
page.actionBarHidden = true;
430+
page.frame.ios._disableNavBarAnimation = false;
431+
} else {
432+
page.actionBarHidden = true;
433+
}
434+
410435
this._actionBarHiddenByTabView = true;
411436
if (Trace.isEnabled()) {
412437
Trace.write(`TabView hid action bar`, Trace.categories.Debug);
@@ -416,9 +441,14 @@ export class TabView extends TabViewBase {
416441
}
417442

418443
if (!backToMoreWillBeVisible && this._actionBarHiddenByTabView) {
419-
page.frame.ios._disableNavBarAnimation = true;
420-
page.actionBarHidden = false;
421-
page.frame.ios._disableNavBarAnimation = false;
444+
if (page.frame.ios) {
445+
page.frame.ios._disableNavBarAnimation = true;
446+
page.actionBarHidden = false;
447+
page.frame.ios._disableNavBarAnimation = false;
448+
} else {
449+
page.actionBarHidden = false;
450+
}
451+
422452
this._actionBarHiddenByTabView = undefined;
423453
if (Trace.isEnabled()) {
424454
Trace.write(`TabView restored action bar`, Trace.categories.Debug);
@@ -457,7 +487,6 @@ export class TabView extends TabViewBase {
457487
const length = items ? items.length : 0;
458488
if (length === 0) {
459489
this._ios.viewControllers = null;
460-
461490
return;
462491
}
463492

0 commit comments

Comments
 (0)