From 6c71ce21a20adba7ea350176fc5a81da646f594f Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Thu, 17 Feb 2022 20:25:41 -0800 Subject: [PATCH] fix(ios): proper UITabBarAppearance handling --- packages/core/ui/tab-view/index.ios.ts | 332 ++++++++++++------------- 1 file changed, 165 insertions(+), 167 deletions(-) diff --git a/packages/core/ui/tab-view/index.ios.ts b/packages/core/ui/tab-view/index.ios.ts index 8e03dfb20..febc7d5a2 100644 --- a/packages/core/ui/tab-view/index.ios.ts +++ b/packages/core/ui/tab-view/index.ios.ts @@ -14,180 +14,168 @@ import { profile } from '../../profiling'; import { Frame } from '../frame'; import { layout, iOSNativeHelper } from '../../utils'; import { Device } from '../../platform'; +import { Transparent } from 'color/known-colors'; export * from './tab-view-common'; const majorVersion = iOSNativeHelper.MajorVersion; const isPhone = Device.deviceType === 'Phone'; -let UITabBarControllerImpl; -let UITabBarControllerDelegateImpl; -let UINavigationControllerDelegateImpl; +@NativeClass +class UITabBarControllerImpl extends UITabBarController { + private _owner: WeakRef; -const setupControllers = function () { - if (typeof UITabBarControllerImpl === 'undefined') { - @NativeClass - class UITabBarControllerClass extends UITabBarController { - private _owner: WeakRef; + public static initWithOwner(owner: WeakRef): UITabBarControllerImpl { + const handler = UITabBarControllerImpl.new(); + handler._owner = owner; - public static initWithOwner(owner: WeakRef): typeof UITabBarControllerImpl { - const handler = UITabBarControllerImpl.new(); - handler._owner = owner; + return handler; + } - return handler; + public viewDidLoad(): void { + super.viewDidLoad(); + + // Unify translucent and opaque bars layout + // this.edgesForExtendedLayout = UIRectEdgeBottom; + this.extendedLayoutIncludesOpaqueBars = true; + } + + @profile + public viewWillAppear(animated: boolean): void { + super.viewWillAppear(animated); + const owner = this._owner.get(); + if (!owner) { + return; + } + + IOSHelper.updateAutoAdjustScrollInsets(this, owner); + + if (!owner.parent) { + owner.callLoaded(); + } + } + + @profile + public viewDidDisappear(animated: boolean): void { + super.viewDidDisappear(animated); + const owner = this._owner.get(); + if (owner && !owner.parent && owner.isLoaded && !this.presentedViewController) { + owner.callUnloaded(); + } + } + + public viewWillTransitionToSizeWithTransitionCoordinator(size: CGSize, coordinator: UIViewControllerTransitionCoordinator): void { + super.viewWillTransitionToSizeWithTransitionCoordinator(size, coordinator); + coordinator.animateAlongsideTransitionCompletion(null, () => { + const owner = this._owner.get(); + if (owner && owner.items) { + owner.items.forEach((tabItem) => tabItem._updateTitleAndIconPositions()); } + }); + } - public viewDidLoad(): void { - super.viewDidLoad(); + // Mind implementation for other controllers + public traitCollectionDidChange(previousTraitCollection: UITraitCollection): void { + super.traitCollectionDidChange(previousTraitCollection); - // Unify translucent and opaque bars layout - // this.edgesForExtendedLayout = UIRectEdgeBottom; - this.extendedLayoutIncludesOpaqueBars = true; - } - - @profile - public viewWillAppear(animated: boolean): void { - super.viewWillAppear(animated); - const owner = this._owner.get(); - if (!owner) { - return; - } - - IOSHelper.updateAutoAdjustScrollInsets(this, owner); - - if (!owner.parent) { - owner.callLoaded(); - } - } - - @profile - public viewDidDisappear(animated: boolean): void { - super.viewDidDisappear(animated); - const owner = this._owner.get(); - if (owner && !owner.parent && owner.isLoaded && !this.presentedViewController) { - owner.callUnloaded(); - } - } - - public viewWillTransitionToSizeWithTransitionCoordinator(size: CGSize, coordinator: UIViewControllerTransitionCoordinator): void { - super.viewWillTransitionToSizeWithTransitionCoordinator(size, coordinator); - coordinator.animateAlongsideTransitionCompletion(null, () => { - const owner = this._owner.get(); - if (owner && owner.items) { - owner.items.forEach((tabItem) => tabItem._updateTitleAndIconPositions()); - } + if (majorVersion >= 13) { + const owner = this._owner.get(); + if (owner && this.traitCollection.hasDifferentColorAppearanceComparedToTraitCollection && this.traitCollection.hasDifferentColorAppearanceComparedToTraitCollection(previousTraitCollection)) { + owner.notify({ + eventName: IOSHelper.traitCollectionColorAppearanceChangedEvent, + object: owner, }); } - - // Mind implementation for other controllers - public traitCollectionDidChange(previousTraitCollection: UITraitCollection): void { - super.traitCollectionDidChange(previousTraitCollection); - - if (majorVersion >= 13) { - const owner = this._owner.get(); - if (owner && this.traitCollection.hasDifferentColorAppearanceComparedToTraitCollection && this.traitCollection.hasDifferentColorAppearanceComparedToTraitCollection(previousTraitCollection)) { - owner.notify({ - eventName: IOSHelper.traitCollectionColorAppearanceChangedEvent, - object: owner, - }); - } - } - } } - UITabBarControllerImpl = UITabBarControllerClass; - - @NativeClass - class UITabBarControllerDelegateClass extends NSObject implements UITabBarControllerDelegate { - public static ObjCProtocols = [UITabBarControllerDelegate]; - - private _owner: WeakRef; - - public static initWithOwner(owner: WeakRef): typeof UITabBarControllerDelegateImpl { - const delegate = UITabBarControllerDelegateImpl.new(); - delegate._owner = owner; - - return delegate; - } - - public tabBarControllerShouldSelectViewController(tabBarController: UITabBarController, viewController: UIViewController): boolean { - if (Trace.isEnabled()) { - Trace.write('TabView.delegate.SHOULD_select(' + tabBarController + ', ' + viewController + ');', Trace.categories.Debug); - } - - const owner = this._owner.get(); - if (owner) { - // "< More" cannot be visible after clicking on the main tab bar buttons. - const backToMoreWillBeVisible = false; - owner._handleTwoNavigationBars(backToMoreWillBeVisible); - } - - if ((tabBarController).selectedViewController === viewController) { - return false; - } - - (tabBarController)._willSelectViewController = viewController; - - return true; - } - - public tabBarControllerDidSelectViewController(tabBarController: UITabBarController, viewController: UIViewController): void { - if (Trace.isEnabled()) { - Trace.write('TabView.delegate.DID_select(' + tabBarController + ', ' + viewController + ');', Trace.categories.Debug); - } - - const owner = this._owner.get(); - if (owner) { - owner._onViewControllerShown(viewController); - } - - (tabBarController)._willSelectViewController = undefined; - } - } - UITabBarControllerDelegateImpl = UITabBarControllerDelegateClass; - - @NativeClass - class UINavigationControllerDelegateClass extends NSObject implements UINavigationControllerDelegate { - public static ObjCProtocols = [UINavigationControllerDelegate]; - - private _owner: WeakRef; - - public static initWithOwner(owner: WeakRef): typeof UINavigationControllerDelegateImpl { - const delegate = UINavigationControllerDelegateImpl.new(); - delegate._owner = owner; - - return delegate; - } - - navigationControllerWillShowViewControllerAnimated(navigationController: UINavigationController, viewController: UIViewController, animated: boolean): void { - if (Trace.isEnabled()) { - Trace.write('TabView.moreNavigationController.WILL_show(' + navigationController + ', ' + viewController + ', ' + animated + ');', Trace.categories.Debug); - } - - const owner = this._owner.get(); - 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); - owner._handleTwoNavigationBars(backToMoreWillBeVisible); - } - } - - navigationControllerDidShowViewControllerAnimated(navigationController: UINavigationController, viewController: UIViewController, animated: boolean): void { - if (Trace.isEnabled()) { - Trace.write('TabView.moreNavigationController.DID_show(' + navigationController + ', ' + viewController + ', ' + animated + ');', Trace.categories.Debug); - } - // We don't need Edit button in More screen. - navigationController.navigationBar.topItem.rightBarButtonItem = null; - const owner = this._owner.get(); - if (owner) { - owner._onViewControllerShown(viewController); - } - } - } - UINavigationControllerDelegateImpl = UINavigationControllerDelegateClass; } -}; +} -setupControllers(); +@NativeClass +class UITabBarControllerDelegateImpl extends NSObject implements UITabBarControllerDelegate { + public static ObjCProtocols = [UITabBarControllerDelegate]; + + private _owner: WeakRef; + + public static initWithOwner(owner: WeakRef): UITabBarControllerDelegateImpl { + const delegate = UITabBarControllerDelegateImpl.new(); + delegate._owner = owner; + + return delegate; + } + + public tabBarControllerShouldSelectViewController(tabBarController: UITabBarController, viewController: UIViewController): boolean { + if (Trace.isEnabled()) { + Trace.write('TabView.delegate.SHOULD_select(' + tabBarController + ', ' + viewController + ');', Trace.categories.Debug); + } + + const owner = this._owner.get(); + if (owner) { + // "< More" cannot be visible after clicking on the main tab bar buttons. + const backToMoreWillBeVisible = false; + owner._handleTwoNavigationBars(backToMoreWillBeVisible); + } + + if ((tabBarController).selectedViewController === viewController) { + return false; + } + + (tabBarController)._willSelectViewController = viewController; + + return true; + } + + public tabBarControllerDidSelectViewController(tabBarController: UITabBarController, viewController: UIViewController): void { + if (Trace.isEnabled()) { + Trace.write('TabView.delegate.DID_select(' + tabBarController + ', ' + viewController + ');', Trace.categories.Debug); + } + + const owner = this._owner.get(); + if (owner) { + owner._onViewControllerShown(viewController); + } + + (tabBarController)._willSelectViewController = undefined; + } +} + +@NativeClass +class UINavigationControllerDelegateImpl extends NSObject implements UINavigationControllerDelegate { + public static ObjCProtocols = [UINavigationControllerDelegate]; + + private _owner: WeakRef; + + public static initWithOwner(owner: WeakRef): UINavigationControllerDelegateImpl { + const delegate = UINavigationControllerDelegateImpl.new(); + delegate._owner = owner; + + return delegate; + } + + navigationControllerWillShowViewControllerAnimated(navigationController: UINavigationController, viewController: UIViewController, animated: boolean): void { + if (Trace.isEnabled()) { + Trace.write('TabView.moreNavigationController.WILL_show(' + navigationController + ', ' + viewController + ', ' + animated + ');', Trace.categories.Debug); + } + + const owner = this._owner.get(); + 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); + owner._handleTwoNavigationBars(backToMoreWillBeVisible); + } + } + + navigationControllerDidShowViewControllerAnimated(navigationController: UINavigationController, viewController: UIViewController, animated: boolean): void { + if (Trace.isEnabled()) { + Trace.write('TabView.moreNavigationController.DID_show(' + navigationController + ', ' + viewController + ', ' + animated + ');', Trace.categories.Debug); + } + // We don't need Edit button in More screen. + navigationController.navigationBar.topItem.rightBarButtonItem = null; + const owner = this._owner.get(); + if (owner) { + owner._onViewControllerShown(viewController); + } + } +} function updateTitleAndIconPositions(tabItem: TabViewItem, tabBarItem: UITabBarItem, controller: UIViewController) { if (!tabItem || !tabBarItem) { @@ -286,11 +274,11 @@ export class TabViewItem extends TabViewItemBase { } export class TabView extends TabViewBase { - public viewController: typeof UITabBarControllerImpl; + public viewController: UITabBarControllerImpl; public items: TabViewItem[]; - public _ios: typeof UITabBarControllerImpl; - private _delegate: typeof UITabBarControllerDelegateImpl; - private _moreNavigationControllerDelegate: typeof UINavigationControllerDelegateImpl; + public _ios: UITabBarControllerImpl; + private _delegate: UITabBarControllerDelegateImpl; + private _moreNavigationControllerDelegate: UINavigationControllerDelegateImpl; private _iconsCache = {}; constructor() { @@ -534,6 +522,17 @@ export class TabView extends TabViewBase { } } + private _getAppearance(tabBar: UITabBar) { + return tabBar.standardAppearance ?? UITabBarAppearance.new(); + } + + private _updateAppearance(tabBar: UITabBar, appearance: UITabBarAppearance) { + tabBar.standardAppearance = appearance; + if (majorVersion >= 15) { + tabBar.scrollEdgeAppearance = appearance; + } + } + [selectedIndexProperty.setNative](value: number) { if (Trace.isEnabled()) { Trace.write('TabView._onSelectedIndexPropertyChangedSetNativeValue(' + value + ')', Trace.categories.Debug); @@ -571,12 +570,11 @@ export class TabView extends TabViewBase { return this._ios.tabBar.barTintColor; } [tabBackgroundColorProperty.setNative](value: UIColor | Color) { - if (majorVersion >= 15) { - let appearance = UITabBarAppearance.new(); + if (majorVersion >= 13) { + const appearance = this._getAppearance(this._ios.tabBar); + appearance.configureWithDefaultBackground(); appearance.backgroundColor = value instanceof Color ? value.ios : value; - - this._ios.tabBar.scrollEdgeAppearance = appearance; - this._ios.tabBar.standardAppearance = appearance; + this._updateAppearance(this._ios.tabBar, appearance); } else { this._ios.tabBar.barTintColor = value instanceof Color ? value.ios : value; }