mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 11:01:21 +08:00
fix(ios): proper UITabBarAppearance handling
This commit is contained in:
@ -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<TabView>;
|
||||
|
||||
const setupControllers = function () {
|
||||
if (typeof UITabBarControllerImpl === 'undefined') {
|
||||
@NativeClass
|
||||
class UITabBarControllerClass extends UITabBarController {
|
||||
private _owner: WeakRef<TabView>;
|
||||
public static initWithOwner(owner: WeakRef<TabView>): UITabBarControllerImpl {
|
||||
const handler = <UITabBarControllerImpl>UITabBarControllerImpl.new();
|
||||
handler._owner = owner;
|
||||
|
||||
public static initWithOwner(owner: WeakRef<TabView>): typeof UITabBarControllerImpl {
|
||||
const handler = <typeof UITabBarControllerImpl>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<TabView>;
|
||||
|
||||
public static initWithOwner(owner: WeakRef<TabView>): typeof UITabBarControllerDelegateImpl {
|
||||
const delegate = <typeof UITabBarControllerDelegateImpl>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 ((<any>tabBarController).selectedViewController === viewController) {
|
||||
return false;
|
||||
}
|
||||
|
||||
(<any>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);
|
||||
}
|
||||
|
||||
(<any>tabBarController)._willSelectViewController = undefined;
|
||||
}
|
||||
}
|
||||
UITabBarControllerDelegateImpl = UITabBarControllerDelegateClass;
|
||||
|
||||
@NativeClass
|
||||
class UINavigationControllerDelegateClass extends NSObject implements UINavigationControllerDelegate {
|
||||
public static ObjCProtocols = [UINavigationControllerDelegate];
|
||||
|
||||
private _owner: WeakRef<TabView>;
|
||||
|
||||
public static initWithOwner(owner: WeakRef<TabView>): typeof UINavigationControllerDelegateImpl {
|
||||
const delegate = <typeof UINavigationControllerDelegateImpl>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<TabView>;
|
||||
|
||||
public static initWithOwner(owner: WeakRef<TabView>): UITabBarControllerDelegateImpl {
|
||||
const delegate = <UITabBarControllerDelegateImpl>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 ((<any>tabBarController).selectedViewController === viewController) {
|
||||
return false;
|
||||
}
|
||||
|
||||
(<any>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);
|
||||
}
|
||||
|
||||
(<any>tabBarController)._willSelectViewController = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@NativeClass
|
||||
class UINavigationControllerDelegateImpl extends NSObject implements UINavigationControllerDelegate {
|
||||
public static ObjCProtocols = [UINavigationControllerDelegate];
|
||||
|
||||
private _owner: WeakRef<TabView>;
|
||||
|
||||
public static initWithOwner(owner: WeakRef<TabView>): UINavigationControllerDelegateImpl {
|
||||
const delegate = <UINavigationControllerDelegateImpl>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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user