diff --git a/packages/core/ui/frame/index.ios.ts b/packages/core/ui/frame/index.ios.ts index 0d0f1f01b9..ef644696c5 100644 --- a/packages/core/ui/frame/index.ios.ts +++ b/packages/core/ui/frame/index.ios.ts @@ -27,10 +27,11 @@ let navControllerDelegate: UINavigationControllerDelegate = null; export class Frame extends FrameBase { viewController: UINavigationControllerImpl; - public _ios: iOSFrame; iosNavigationBarClass: typeof NSObject; iosToolbarClass: typeof NSObject; + private _ios: iOSFrame; + constructor() { super(); this._ios = new iOSFrame(this); @@ -43,7 +44,13 @@ export class Frame extends FrameBase { this._pushInFrameStack(); } - return this.viewController.view; + // View controller can be disposed during view disposal, so make sure to create a new one if not defined + if (!this._ios) { + this._ios = new iOSFrame(this); + this.viewController = this._ios.controller; + } + + return this._ios.controller.view; } public disposeNativeView() { @@ -726,9 +733,7 @@ export function _getNativeCurve(transition: NavigationTransition): UIViewAnimati return UIViewAnimationCurve.EaseInOut; } -/* tslint:disable */ class iOSFrame implements iOSFrameDefinition { - /* tslint:enable */ private _controller: UINavigationControllerImpl; private _showNavigationBar: boolean; private _navBarVisibility: 'auto' | 'never' | 'always' = 'auto'; diff --git a/packages/core/ui/page/index.ios.ts b/packages/core/ui/page/index.ios.ts index ee2b2519c0..50c2a124c3 100644 --- a/packages/core/ui/page/index.ios.ts +++ b/packages/core/ui/page/index.ios.ts @@ -377,7 +377,13 @@ export class Page extends PageBase { } createNativeView() { - return this.viewController.view; + // View controller can be disposed during view disposal, so make sure to create a new one if not defined + if (!this._ios) { + const controller = UIViewControllerImpl.initWithOwner(new WeakRef(this)); + controller.view.backgroundColor = this._backgroundColor; + this.viewController = this._ios = controller; + } + return this._ios.view; } disposeNativeView() { @@ -438,7 +444,7 @@ export class Page extends PageBase { public _updateStatusBarStyle(value?: string) { const frame = this.frame; - if (frame && value) { + if (frame?.ios && value) { const navigationController: UINavigationController = frame.ios.controller; const navigationBar = navigationController.navigationBar; @@ -488,7 +494,7 @@ export class Page extends PageBase { const insets = this.getSafeAreaInsets(); - if (!__VISIONOS__ && SDK_VERSION <= 10) { + if (!__VISIONOS__ && SDK_VERSION <= 10 && this.viewController) { // iOS 10 and below don't have safe area insets API, // there we need only the top inset on the Page insets.top = layout.round(layout.toDevicePixels(this.viewController.view.safeAreaLayoutGuide.layoutFrame.origin.y)); diff --git a/packages/core/ui/tab-view/index.ios.ts b/packages/core/ui/tab-view/index.ios.ts index 7680586c4e..62f1b2b599 100644 --- a/packages/core/ui/tab-view/index.ios.ts +++ b/packages/core/ui/tab-view/index.ios.ts @@ -108,8 +108,7 @@ class UITabBarControllerDelegateImpl extends NSObject implements UITabBarControl const owner = this._owner?.deref(); if (owner) { // "< More" cannot be visible after clicking on the main tab bar buttons. - const backToMoreWillBeVisible = false; - owner._handleTwoNavigationBars(backToMoreWillBeVisible); + owner._handleTwoNavigationBars(false); } if (tabBarController.selectedViewController === viewController) { @@ -126,7 +125,7 @@ class UITabBarControllerDelegateImpl extends NSObject implements UITabBarControl const owner = this._owner?.deref(); if (owner) { - owner._onViewControllerShown(viewController); + owner._onViewControllerShown(tabBarController, viewController); } } } @@ -153,7 +152,7 @@ class UINavigationControllerDelegateImpl extends NSObject implements UINavigatio if (owner) { // If viewController is one of our tab item controllers, then "< More" will be visible shortly. // Otherwise viewController is the UIMoreListController which shows the list of all tabs beyond the 4th tab. - const backToMoreWillBeVisible = owner._ios.viewControllers.containsObject(viewController); + const backToMoreWillBeVisible = navigationController.tabBarController?.viewControllers?.containsObject(viewController); owner._handleTwoNavigationBars(backToMoreWillBeVisible); } } @@ -166,7 +165,7 @@ class UINavigationControllerDelegateImpl extends NSObject implements UINavigatio navigationController.navigationBar.topItem.rightBarButtonItem = null; const owner = this._owner?.deref(); if (owner) { - owner._onViewControllerShown(viewController); + owner._onViewControllerShown(navigationController.tabBarController, viewController); } } } @@ -273,16 +272,24 @@ export class TabViewItem extends TabViewItemBase { export class TabView extends TabViewBase { public viewController: UITabBarControllerImpl; public items: TabViewItem[]; - public _ios: UITabBarControllerImpl; + private _delegate: UITabBarControllerDelegateImpl; private _moreNavigationControllerDelegate: UINavigationControllerDelegateImpl; private _iconsCache = {}; + private _ios: UITabBarControllerImpl; + private _actionBarHiddenByTabView: boolean; constructor() { super(); - this.viewController = this._ios = UITabBarControllerImpl.initWithOwner(new WeakRef(this)); - this.nativeViewProtected = this._ios.view; + } + + createNativeView() { + // View controller can be disposed during view disposal, so make sure to create a new one if not defined + if (!this._ios) { + this.viewController = this._ios = UITabBarControllerImpl.initWithOwner(new WeakRef(this)); + } + return this._ios.view; } initNativeView() { @@ -294,6 +301,8 @@ export class TabView extends TabViewBase { disposeNativeView() { this._delegate = null; this._moreNavigationControllerDelegate = null; + this.viewController = null; + this._ios = null; super.disposeNativeView(); } @@ -307,12 +316,19 @@ export class TabView extends TabViewBase { selectedView._pushInFrameStackRecursive(); } - this._ios.delegate = this._delegate; + if (this._ios) { + this._ios.delegate = this._delegate; + } } public onUnloaded() { - this._ios.delegate = null; - this._ios.moreNavigationController.delegate = null; + if (this._ios) { + this._ios.delegate = null; + + if (this._ios.moreNavigationController) { + this._ios.moreNavigationController.delegate = null; + } + } super.onUnloaded(); } @@ -366,13 +382,13 @@ export class TabView extends TabViewBase { this.setMeasuredDimension(widthAndState, heightAndState); } - public _onViewControllerShown(viewController: UIViewController) { + public _onViewControllerShown(tabBarController: UITabBarController, viewController: UIViewController) { // This method could be called with the moreNavigationController or its list controller, so we have to check. if (Trace.isEnabled()) { Trace.write('TabView._onViewControllerShown(' + viewController + ');', Trace.categories.Debug); } - if (this._ios.viewControllers && this._ios.viewControllers.containsObject(viewController)) { - this.selectedIndex = this._ios.viewControllers.indexOfObject(viewController); + if (tabBarController?.viewControllers && tabBarController.viewControllers.containsObject(viewController)) { + this.selectedIndex = tabBarController.viewControllers.indexOfObject(viewController); } else { if (Trace.isEnabled()) { Trace.write('TabView._onViewControllerShown: viewController is not one of our viewControllers', Trace.categories.Debug); @@ -380,14 +396,18 @@ export class TabView extends TabViewBase { } } - private _actionBarHiddenByTabView: boolean; public _handleTwoNavigationBars(backToMoreWillBeVisible: boolean) { if (Trace.isEnabled()) { Trace.write(`TabView._handleTwoNavigationBars(backToMoreWillBeVisible: ${backToMoreWillBeVisible})`, Trace.categories.Debug); } // The "< Back" and "< More" navigation bars should not be visible simultaneously. - const page = this.page || this._selectedView?.page || (this)._selectedView?.currentPage; + let page = this.page || this._selectedView?.page; + + if (!page && this._selectedView instanceof Frame) { + page = this._selectedView.currentPage; + } + if (!page || !page.frame) { return; } @@ -395,9 +415,14 @@ export class TabView extends TabViewBase { const actionBarVisible = page.frame._getNavBarVisible(page); if (backToMoreWillBeVisible && actionBarVisible) { - page.frame.ios._disableNavBarAnimation = true; - page.actionBarHidden = true; - page.frame.ios._disableNavBarAnimation = false; + if (page.frame.ios) { + page.frame.ios._disableNavBarAnimation = true; + page.actionBarHidden = true; + page.frame.ios._disableNavBarAnimation = false; + } else { + page.actionBarHidden = true; + } + this._actionBarHiddenByTabView = true; if (Trace.isEnabled()) { Trace.write(`TabView hid action bar`, Trace.categories.Debug); @@ -407,9 +432,14 @@ export class TabView extends TabViewBase { } if (!backToMoreWillBeVisible && this._actionBarHiddenByTabView) { - page.frame.ios._disableNavBarAnimation = true; - page.actionBarHidden = false; - page.frame.ios._disableNavBarAnimation = false; + if (page.frame.ios) { + page.frame.ios._disableNavBarAnimation = true; + page.actionBarHidden = false; + page.frame.ios._disableNavBarAnimation = false; + } else { + page.actionBarHidden = false; + } + this._actionBarHiddenByTabView = undefined; if (Trace.isEnabled()) { Trace.write(`TabView restored action bar`, Trace.categories.Debug); @@ -448,7 +478,6 @@ export class TabView extends TabViewBase { const length = items ? items.length : 0; if (length === 0) { this._ios.viewControllers = null; - return; }