mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-16 11:42:04 +08:00
Merge branch 'master' into fix_css_styles
This commit is contained in:
1
nativescript-core/css/css-tree-parser.d.ts
vendored
Normal file
1
nativescript-core/css/css-tree-parser.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
export declare function cssTreeParse(css: any, source: any): any;
|
@ -14,6 +14,7 @@
|
||||
"Foundation.*:*",
|
||||
|
||||
"MaterialComponents.MDCTabBar:*",
|
||||
"MaterialComponents.MDCTabBarIndicatorTemplate:*",
|
||||
|
||||
"NativeScriptEmbedder:*",
|
||||
|
||||
|
@ -442,13 +442,17 @@ declare class MDCTabBar extends UIView implements UIBarPositioning {
|
||||
|
||||
delegate: MDCTabBarDelegate;
|
||||
|
||||
displaysUppercaseTitles: boolean;
|
||||
displaysUppercaseTitles: boolean;
|
||||
|
||||
inkColor: UIColor;
|
||||
enableRippleBehavior: boolean;
|
||||
|
||||
itemAppearance: MDCTabBarItemAppearance;
|
||||
inkColor: UIColor;
|
||||
|
||||
items: NSArray<UITabBarItem>;
|
||||
itemAppearance: MDCTabBarItemAppearance;
|
||||
|
||||
items: NSArray<UITabBarItem>;
|
||||
|
||||
rippleColor: UIColor;
|
||||
|
||||
selectedItem: UITabBarItem;
|
||||
|
||||
|
@ -36,6 +36,11 @@ let BottomNavigationBar: any;
|
||||
let AttachStateChangeListener: any;
|
||||
let appResources: android.content.res.Resources;
|
||||
|
||||
class IconInfo {
|
||||
drawable: android.graphics.drawable.BitmapDrawable;
|
||||
height: number;
|
||||
}
|
||||
|
||||
function makeFragmentName(viewId: number, id: number): string {
|
||||
return "android:bottomnavigation:" + viewId + ":" + id;
|
||||
}
|
||||
@ -243,6 +248,7 @@ export class BottomNavigation extends TabNavigationBase {
|
||||
private _currentTransaction: androidx.fragment.app.FragmentTransaction;
|
||||
private _attachedToWindow = false;
|
||||
public _originalBackground: any;
|
||||
private _textTransform: TextTransform = "none";
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@ -562,6 +568,18 @@ export class BottomNavigation extends TabNavigationBase {
|
||||
});
|
||||
}
|
||||
|
||||
private getItemLabelTextTransform(tabStripItem: TabStripItem): TextTransform {
|
||||
const nestedLabel = tabStripItem.label;
|
||||
let textTransform: TextTransform = null;
|
||||
if (nestedLabel && nestedLabel.style.textTransform !== "initial") {
|
||||
textTransform = nestedLabel.style.textTransform;
|
||||
} else if (tabStripItem.style.textTransform !== "initial") {
|
||||
textTransform = tabStripItem.style.textTransform;
|
||||
}
|
||||
|
||||
return textTransform || this._textTransform;
|
||||
}
|
||||
|
||||
private createTabItemSpec(tabStripItem: TabStripItem): org.nativescript.widgets.TabItemSpec {
|
||||
const tabItemSpec = new org.nativescript.widgets.TabItemSpec();
|
||||
|
||||
@ -570,10 +588,8 @@ export class BottomNavigation extends TabNavigationBase {
|
||||
let title = titleLabel.text;
|
||||
|
||||
// TEXT-TRANSFORM
|
||||
const textTransform = titleLabel.style.textTransform;
|
||||
if (textTransform) {
|
||||
title = getTransformedText(title, textTransform);
|
||||
}
|
||||
const textTransform = this.getItemLabelTextTransform(tabStripItem);
|
||||
title = getTransformedText(title, textTransform);
|
||||
tabItemSpec.title = title;
|
||||
|
||||
// BACKGROUND-COLOR
|
||||
@ -596,12 +612,13 @@ export class BottomNavigation extends TabNavigationBase {
|
||||
// ICON
|
||||
const iconSource = tabStripItem.image && tabStripItem.image.src;
|
||||
if (iconSource) {
|
||||
const icon = this.getIcon(tabStripItem);
|
||||
const iconInfo = this.getIconInfo(tabStripItem);
|
||||
|
||||
if (icon) {
|
||||
if (iconInfo) {
|
||||
// TODO: Make this native call that accepts string so that we don't load Bitmap in JS.
|
||||
// tslint:disable-next-line:deprecation
|
||||
tabItemSpec.iconDrawable = icon;
|
||||
tabItemSpec.iconDrawable = iconInfo.drawable;
|
||||
tabItemSpec.imageHeight = iconInfo.height;
|
||||
} else {
|
||||
// TODO:
|
||||
// traceMissingIcon(iconSource);
|
||||
@ -612,7 +629,7 @@ export class BottomNavigation extends TabNavigationBase {
|
||||
return tabItemSpec;
|
||||
}
|
||||
|
||||
private getIcon(tabStripItem: TabStripItem): android.graphics.drawable.BitmapDrawable {
|
||||
private getOriginalIcon(tabStripItem: TabStripItem): android.graphics.Bitmap {
|
||||
const iconSource = tabStripItem.image && tabStripItem.image.src;
|
||||
if (!iconSource) {
|
||||
return null;
|
||||
@ -629,21 +646,30 @@ export class BottomNavigation extends TabNavigationBase {
|
||||
is = ImageSource.fromFileOrResourceSync(iconSource);
|
||||
}
|
||||
|
||||
let imageDrawable: android.graphics.drawable.BitmapDrawable;
|
||||
if (is && is.android) {
|
||||
let image = is.android;
|
||||
return is && is.android;
|
||||
}
|
||||
|
||||
private getDrawableInfo(image: android.graphics.Bitmap): IconInfo {
|
||||
if (image) {
|
||||
if (this.tabStrip && this.tabStrip.isIconSizeFixed) {
|
||||
image = this.getFixedSizeIcon(image);
|
||||
}
|
||||
|
||||
imageDrawable = new android.graphics.drawable.BitmapDrawable(application.android.context.getResources(), image);
|
||||
} else {
|
||||
// TODO
|
||||
// traceMissingIcon(iconSource);
|
||||
let imageDrawable = new android.graphics.drawable.BitmapDrawable(application.android.context.getResources(), image);
|
||||
|
||||
return {
|
||||
drawable: imageDrawable,
|
||||
height: image.getHeight()
|
||||
};
|
||||
}
|
||||
|
||||
return imageDrawable;
|
||||
return new IconInfo();
|
||||
}
|
||||
|
||||
private getIconInfo(tabStripItem: TabStripItem): IconInfo {
|
||||
let originalIcon = this.getOriginalIcon(tabStripItem);
|
||||
|
||||
return this.getDrawableInfo(originalIcon);
|
||||
}
|
||||
|
||||
private getFixedSizeIcon(image: android.graphics.Bitmap): android.graphics.Bitmap {
|
||||
@ -702,9 +728,9 @@ export class BottomNavigation extends TabNavigationBase {
|
||||
const index = tabStripItem._index;
|
||||
const tabBarItem = this._bottomNavigationBar.getViewForItemAt(index);
|
||||
const imgView = <android.widget.ImageView>tabBarItem.getChildAt(0);
|
||||
const drawable = this.getIcon(tabStripItem);
|
||||
const drawableInfo = this.getIconInfo(tabStripItem);
|
||||
|
||||
imgView.setImageDrawable(drawable);
|
||||
imgView.setImageDrawable(drawableInfo.drawable);
|
||||
}
|
||||
|
||||
public setTabBarItemFontInternal(tabStripItem: TabStripItem, value: Font): void {
|
||||
@ -721,6 +747,24 @@ export class BottomNavigation extends TabNavigationBase {
|
||||
tabStripItem.nativeViewProtected.setText(title);
|
||||
}
|
||||
|
||||
public getTabBarTextTransform(): TextTransform {
|
||||
return this._textTransform;
|
||||
}
|
||||
|
||||
public setTabBarTextTransform(value: TextTransform): void {
|
||||
let items = this.tabStrip && this.tabStrip.items;
|
||||
if (items) {
|
||||
items.forEach((tabStripItem) => {
|
||||
if (tabStripItem.label && tabStripItem.nativeViewProtected) {
|
||||
const nestedLabel = tabStripItem.label;
|
||||
const title = getTransformedText(nestedLabel.text, value);
|
||||
tabStripItem.nativeViewProtected.setText(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
this._textTransform = value;
|
||||
}
|
||||
|
||||
[selectedIndexProperty.setNative](value: number) {
|
||||
// const smoothScroll = false;
|
||||
|
||||
|
@ -71,20 +71,19 @@ class UITabBarControllerImpl extends UITabBarController {
|
||||
|
||||
public viewWillTransitionToSizeWithTransitionCoordinator(size: CGSize, coordinator: UIViewControllerTransitionCoordinator): void {
|
||||
super.viewWillTransitionToSizeWithTransitionCoordinator(size, coordinator);
|
||||
UIViewControllerTransitionCoordinator.prototype.animateAlongsideTransitionCompletion
|
||||
.call(coordinator, () => {
|
||||
const owner = this._owner.get();
|
||||
if (owner && owner.tabStrip && owner.tabStrip.items) {
|
||||
const tabStrip = owner.tabStrip;
|
||||
tabStrip.items.forEach(tabStripItem => {
|
||||
updateBackgroundPositions(tabStrip, tabStripItem);
|
||||
coordinator.animateAlongsideTransitionCompletion(() => {
|
||||
const owner = this._owner.get();
|
||||
if (owner && owner.tabStrip && owner.tabStrip.items) {
|
||||
const tabStrip = owner.tabStrip;
|
||||
tabStrip.items.forEach(tabStripItem => {
|
||||
updateBackgroundPositions(tabStrip, tabStripItem);
|
||||
|
||||
const index = tabStripItem._index;
|
||||
const tabBarItemController = this.viewControllers[index];
|
||||
updateTitleAndIconPositions(tabStripItem, tabBarItemController.tabBarItem, tabBarItemController);
|
||||
});
|
||||
}
|
||||
}, null);
|
||||
const index = tabStripItem._index;
|
||||
const tabBarItemController = this.viewControllers[index];
|
||||
updateTitleAndIconPositions(tabStripItem, tabBarItemController.tabBarItem, tabBarItemController);
|
||||
});
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
|
||||
// Mind implementation for other controllers
|
||||
@ -207,17 +206,14 @@ class UINavigationControllerDelegateImpl extends NSObject implements UINavigatio
|
||||
|
||||
function updateBackgroundPositions(tabStrip: TabStrip, tabStripItem: TabStripItem) {
|
||||
let bgView = (<any>tabStripItem).bgView;
|
||||
const index = tabStripItem._index;
|
||||
const width = tabStrip.nativeView.frame.size.width / tabStrip.items.length;
|
||||
const frame = CGRectMake(width * index, 0, width, tabStrip.nativeView.frame.size.width);
|
||||
if (!bgView) {
|
||||
const index = tabStripItem._index;
|
||||
const width = tabStrip.nativeView.frame.size.width / tabStrip.items.length;
|
||||
const frame = CGRectMake(width * index, 0, width, tabStrip.nativeView.frame.size.width);
|
||||
bgView = UIView.alloc().initWithFrame(frame);
|
||||
tabStrip.nativeView.insertSubviewAtIndex(bgView, 0);
|
||||
(<any>tabStripItem).bgView = bgView;
|
||||
} else {
|
||||
const index = tabStripItem._index;
|
||||
const width = tabStrip.nativeView.frame.size.width / tabStrip.items.length;
|
||||
const frame = CGRectMake(width * index, 0, width, tabStrip.nativeView.frame.size.width);
|
||||
bgView.frame = frame;
|
||||
}
|
||||
|
||||
@ -376,8 +372,7 @@ export class BottomNavigation extends TabNavigationBase {
|
||||
}
|
||||
|
||||
public setTabBarItemColor(tabStripItem: TabStripItem, value: UIColor | Color): void {
|
||||
const states = getTitleAttributesForStates(tabStripItem.label);
|
||||
applyStatesToItem(tabStripItem.nativeView, states, this.viewController.tabBar);
|
||||
setViewTextAttributes(tabStripItem.nativeView, tabStripItem.label, this.viewController.tabBar);
|
||||
}
|
||||
|
||||
public setTabBarIconColor(tabStripItem: TabStripItem, value: UIColor | Color): void {
|
||||
@ -388,8 +383,7 @@ export class BottomNavigation extends TabNavigationBase {
|
||||
}
|
||||
|
||||
public setTabBarItemFontInternal(tabStripItem: TabStripItem, value: Font): void {
|
||||
const states = getTitleAttributesForStates(tabStripItem.label);
|
||||
applyStatesToItem(tabStripItem.nativeView, states, this.viewController.tabBar);
|
||||
setViewTextAttributes(tabStripItem.nativeView, tabStripItem.label, this.viewController.tabBar);
|
||||
}
|
||||
|
||||
public setTabBarItemTextTransform(tabStripItem: TabStripItem, value: TextTransform): void {
|
||||
@ -397,6 +391,15 @@ export class BottomNavigation extends TabNavigationBase {
|
||||
tabStripItem.nativeView.title = title;
|
||||
}
|
||||
|
||||
public getTabBarHighlightColor(): UIColor {
|
||||
return this._ios.tabBar.tintColor;
|
||||
}
|
||||
|
||||
public setTabBarHighlightColor(value: UIColor | Color) {
|
||||
const nativeColor = value instanceof Color ? value.ios : value;
|
||||
this._ios.tabBar.tintColor = nativeColor;
|
||||
}
|
||||
|
||||
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
|
||||
const width = layout.getMeasureSpecSize(widthMeasureSpec);
|
||||
const widthMode = layout.getMeasureSpecMode(widthMeasureSpec);
|
||||
@ -518,8 +521,7 @@ export class BottomNavigation extends TabNavigationBase {
|
||||
const tabBarItem = this.createTabBarItem(tabStripItem, i);
|
||||
updateTitleAndIconPositions(tabStripItem, tabBarItem, controller);
|
||||
|
||||
const states = getTitleAttributesForStates(tabStripItem.label);
|
||||
applyStatesToItem(tabBarItem, states, this.viewController.tabBar);
|
||||
setViewTextAttributes(tabBarItem, tabStripItem.label, this.viewController.tabBar);
|
||||
|
||||
controller.tabBarItem = tabBarItem;
|
||||
tabStripItem._index = i;
|
||||
@ -688,51 +690,31 @@ export class BottomNavigation extends TabNavigationBase {
|
||||
}
|
||||
}
|
||||
|
||||
interface TabStates {
|
||||
normalState?: any;
|
||||
selectedState?: any;
|
||||
}
|
||||
|
||||
function getTitleAttributesForStates(view: View): TabStates {
|
||||
function setViewTextAttributes(item: UITabBarItem, view: View, tabBar: UITabBar): any {
|
||||
if (!view) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const result: TabStates = {};
|
||||
const defaultTabItemFontSize = 10;
|
||||
const tabItemFontSize = view.style.fontSize || defaultTabItemFontSize;
|
||||
const font: UIFont = view.style.fontInternal.getUIFont(UIFont.systemFontOfSize(tabItemFontSize));
|
||||
const tabItemTextColor = view.style.color;
|
||||
const textColor = tabItemTextColor instanceof Color ? tabItemTextColor.ios : null;
|
||||
result.normalState = { [NSFontAttributeName]: font };
|
||||
let attributes: any = { [NSFontAttributeName]: font };
|
||||
if (textColor) {
|
||||
result.normalState[UITextAttributeTextColor] = textColor;
|
||||
attributes[UITextAttributeTextColor] = textColor;
|
||||
attributes[NSForegroundColorAttributeName] = textColor;
|
||||
}
|
||||
|
||||
const tabSelectedItemTextColor = view.style.color;
|
||||
const selectedTextColor = tabSelectedItemTextColor instanceof Color ? tabSelectedItemTextColor.ios : null;
|
||||
result.selectedState = { [NSFontAttributeName]: font };
|
||||
if (selectedTextColor) {
|
||||
result.selectedState[UITextAttributeTextColor] = selectedTextColor;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function applyStatesToItem(item: UITabBarItem, states: TabStates, tabBar: UITabBar) {
|
||||
if (!states) {
|
||||
return;
|
||||
}
|
||||
|
||||
item.setTitleTextAttributesForState(states.normalState, UIControlState.Normal);
|
||||
item.setTitleTextAttributesForState(states.selectedState, UIControlState.Selected);
|
||||
item.setTitleTextAttributesForState(attributes, UIControlState.Selected);
|
||||
item.setTitleTextAttributesForState(attributes, UIControlState.Normal);
|
||||
|
||||
// there's a bug when setting the item color on ios 13 if there's no background set to the tabstrip
|
||||
// https://books.google.bg/books?id=99_BDwAAQBAJ&q=tabBar.unselectedItemTintColor
|
||||
// to fix the above issue we are applying the selected fix only for the case, when there is no background set
|
||||
// in that case we have the following known issue:
|
||||
// we will set the color to all unselected items, so you won't be able to set different colors for the different not selected items
|
||||
if (!tabBar.barTintColor && states.normalState[UITextAttributeTextColor] && (majorVersion > 9)) {
|
||||
tabBar.unselectedItemTintColor = states.normalState[UITextAttributeTextColor];
|
||||
if (!tabBar.barTintColor && attributes[UITextAttributeTextColor] && (majorVersion > 9)) {
|
||||
tabBar.unselectedItemTintColor = attributes[UITextAttributeTextColor];
|
||||
}
|
||||
}
|
||||
}
|
@ -26,6 +26,7 @@ import { sanitizeModuleName } from "../../builder/module-name-sanitizer";
|
||||
import { StyleScope } from "../../styling/style-scope";
|
||||
import { LinearGradient } from "../../styling/linear-gradient";
|
||||
import { BackgroundRepeat } from "../../styling/style-properties";
|
||||
import { TextTransform } from "../../text-base";
|
||||
|
||||
export * from "../../styling/style-properties";
|
||||
export * from "../view-base";
|
||||
@ -718,6 +719,13 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
|
||||
this.style.perspective = value;
|
||||
}
|
||||
|
||||
get textTransform(): TextTransform {
|
||||
return this.style.textTransform;
|
||||
}
|
||||
set textTransform(value: TextTransform) {
|
||||
this.style.textTransform = value;
|
||||
}
|
||||
|
||||
get translateX(): dip {
|
||||
return this.style.translateX;
|
||||
}
|
||||
|
@ -1116,7 +1116,7 @@ function createNativePercentLengthProperty(options: NativePercentLengthPropertyO
|
||||
setPercent = options.setPercent || percentNotSupported;
|
||||
options = null;
|
||||
}
|
||||
if (length == "auto") { // tslint:disable-line
|
||||
if (length == "auto" || !length) { // tslint:disable-line
|
||||
setPixels(this.nativeViewProtected, auto);
|
||||
} else if (typeof length === "number") {
|
||||
setPixels(this.nativeViewProtected, layout.round(layout.toDevicePixels(length)));
|
||||
|
@ -180,7 +180,7 @@ export class View extends ViewCommon implements ViewDefinition {
|
||||
if (adjustedFrame) {
|
||||
nativeView.frame = adjustedFrame;
|
||||
}
|
||||
|
||||
|
||||
if (this._hasTransfrom) {
|
||||
// re-apply the transform after the frame is adjusted
|
||||
nativeView.layer.transform = transform;
|
||||
@ -359,7 +359,7 @@ export class View extends ViewCommon implements ViewDefinition {
|
||||
if (this.rotateX || this.rotateY) {
|
||||
transform.m34 = -1 / perspective;
|
||||
}
|
||||
|
||||
|
||||
transform = CATransform3DTranslate(transform, this.translateX, this.translateY, 0);
|
||||
transform = iosNativeHelper.applyRotateTransform(transform, this.rotateX, this.rotateY, this.rotate);
|
||||
transform = CATransform3DScale(transform, scaleX, scaleY, 1);
|
||||
@ -479,8 +479,7 @@ export class View extends ViewCommon implements ViewDefinition {
|
||||
parentController.presentViewControllerAnimatedCompletion(controller, animated, null);
|
||||
const transitionCoordinator = parentController.transitionCoordinator;
|
||||
if (transitionCoordinator) {
|
||||
UIViewControllerTransitionCoordinator.prototype.animateAlongsideTransitionCompletion
|
||||
.call(transitionCoordinator, null, () => this._raiseShownModallyEvent());
|
||||
transitionCoordinator.animateAlongsideTransitionCompletion(null, () => this._raiseShownModallyEvent());
|
||||
} else {
|
||||
// Apparently iOS 9+ stops all transitions and animations upon application suspend and transitionCoordinator becomes null here in this case.
|
||||
// Since we are not waiting for any transition to complete, i.e. transitionCoordinator is null, we can directly raise our shownModally event.
|
||||
|
2
nativescript-core/ui/index.d.ts
vendored
2
nativescript-core/ui/index.d.ts
vendored
@ -34,7 +34,7 @@ export { TabNavigationBase } from "./tab-navigation-base/tab-navigation-base";
|
||||
export { TabStrip, TabStripItemEventData } from "./tab-navigation-base/tab-strip";
|
||||
export { TabStripItem } from "./tab-navigation-base/tab-strip-item";
|
||||
export { TabView, TabViewItem } from "./tab-view";
|
||||
export { Tabs } from "./tabs";
|
||||
export { Tabs, IOSTabBarItemsAlignment } from "./tabs";
|
||||
export { TextBase } from "./text-base";
|
||||
export { FormattedString } from "./text-base/formatted-string";
|
||||
export { Span } from "./text-base/span";
|
||||
|
@ -286,4 +286,4 @@ export const tabStripProperty = new Property<TabNavigationBase, TabStrip>({
|
||||
target.onTabStripChanged(oldValue, newValue);
|
||||
}
|
||||
});
|
||||
tabStripProperty.register(TabNavigationBase);
|
||||
tabStripProperty.register(TabNavigationBase);
|
@ -13,6 +13,7 @@ import {
|
||||
import { isIOS } from "../../../platform";
|
||||
import { Image } from "../../image/image";
|
||||
import { Label } from "../../label/label";
|
||||
import { textTransformProperty, TextTransform } from "../../text-base";
|
||||
|
||||
export * from "../../core/view";
|
||||
export const traceCategory = "TabView";
|
||||
@ -236,6 +237,19 @@ export class TabStripItem extends View implements TabStripItemDefinition, AddChi
|
||||
return tabStripParent && tabStripParent.setTabBarItemBackgroundColor(this, value);
|
||||
}
|
||||
|
||||
[textTransformProperty.getDefault](): TextTransform {
|
||||
const parent = <TabStrip>this.parent;
|
||||
const tabStripParent = parent && <TabNavigationBase>parent.parent;
|
||||
|
||||
return tabStripParent && tabStripParent.getTabBarItemTextTransform(this);
|
||||
}
|
||||
[textTransformProperty.setNative](value: TextTransform) {
|
||||
const parent = <TabStrip>this.parent;
|
||||
const tabStripParent = parent && <TabNavigationBase>parent.parent;
|
||||
|
||||
return tabStripParent && tabStripParent.setTabBarItemTextTransform(this, value);
|
||||
}
|
||||
|
||||
[backgroundInternalProperty.getDefault](): any {
|
||||
return null;
|
||||
}
|
||||
|
@ -63,13 +63,12 @@ class UITabBarControllerImpl extends UITabBarController {
|
||||
|
||||
public viewWillTransitionToSizeWithTransitionCoordinator(size: CGSize, coordinator: UIViewControllerTransitionCoordinator): void {
|
||||
super.viewWillTransitionToSizeWithTransitionCoordinator(size, coordinator);
|
||||
UIViewControllerTransitionCoordinator.prototype.animateAlongsideTransitionCompletion
|
||||
.call(coordinator, null, () => {
|
||||
const owner = this._owner.get();
|
||||
if (owner && owner.items) {
|
||||
owner.items.forEach(tabItem => tabItem._updateTitleAndIconPositions());
|
||||
}
|
||||
});
|
||||
coordinator.animateAlongsideTransitionCompletion(null, () => {
|
||||
const owner = this._owner.get();
|
||||
if (owner && owner.items) {
|
||||
owner.items.forEach(tabItem => tabItem._updateTitleAndIconPositions());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Mind implementation for other controllers
|
||||
|
@ -22,6 +22,7 @@ export class TabsBase extends TabNavigationBase implements TabsDefinition {
|
||||
public swipeEnabled: boolean;
|
||||
public offscreenTabLimit: number;
|
||||
public tabsPosition: "top" | "bottom";
|
||||
public iOSTabBarItemsAlignment: IOSTabBarItemsAlignment;
|
||||
}
|
||||
|
||||
// TODO: Add Unit tests
|
||||
@ -39,3 +40,7 @@ offscreenTabLimitProperty.register(TabsBase);
|
||||
|
||||
export const tabsPositionProperty = new Property<TabsBase, "top" | "bottom">({ name: "tabsPosition", defaultValue: "top" });
|
||||
tabsPositionProperty.register(TabsBase);
|
||||
|
||||
export type IOSTabBarItemsAlignment = "leading" | "justified" | "center" | "centerSelected";
|
||||
export const iOSTabBarItemsAlignmentProperty = new Property<TabsBase, IOSTabBarItemsAlignment>({ name: "iOSTabBarItemsAlignment", defaultValue: "justified" });
|
||||
iOSTabBarItemsAlignmentProperty.register(TabsBase);
|
@ -373,6 +373,7 @@ export class Tabs extends TabsBase {
|
||||
private _pagerAdapter: androidx.viewpager.widget.PagerAdapter;
|
||||
private _androidViewId: number = -1;
|
||||
public _originalBackground: any;
|
||||
private _textTransform: TextTransform = "uppercase";
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@ -637,6 +638,18 @@ export class Tabs extends TabsBase {
|
||||
});
|
||||
}
|
||||
|
||||
private getItemLabelTextTransform(tabStripItem: TabStripItem): TextTransform {
|
||||
const nestedLabel = tabStripItem.label;
|
||||
let textTransform: TextTransform = null;
|
||||
if (nestedLabel && nestedLabel.style.textTransform !== "initial") {
|
||||
textTransform = nestedLabel.style.textTransform;
|
||||
} else if (tabStripItem.style.textTransform !== "initial") {
|
||||
textTransform = tabStripItem.style.textTransform;
|
||||
}
|
||||
|
||||
return textTransform || this._textTransform;
|
||||
}
|
||||
|
||||
private createTabItemSpec(tabStripItem: TabStripItem): org.nativescript.widgets.TabItemSpec {
|
||||
const tabItemSpec = new org.nativescript.widgets.TabItemSpec();
|
||||
|
||||
@ -645,10 +658,8 @@ export class Tabs extends TabsBase {
|
||||
let title = nestedLabel.text;
|
||||
|
||||
// TEXT-TRANSFORM
|
||||
const textTransform = nestedLabel.style.textTransform;
|
||||
if (textTransform) {
|
||||
title = getTransformedText(title, textTransform);
|
||||
}
|
||||
const textTransform = this.getItemLabelTextTransform(tabStripItem);
|
||||
title = getTransformedText(title, textTransform);
|
||||
tabItemSpec.title = title;
|
||||
|
||||
// BACKGROUND-COLOR
|
||||
@ -817,7 +828,7 @@ export class Tabs extends TabsBase {
|
||||
const tabBarItem = this._tabsBar.getViewForItemAt(index);
|
||||
const imgView = <android.widget.ImageView>tabBarItem.getChildAt(0);
|
||||
const drawable = this.getIcon(tabStripItem);
|
||||
|
||||
|
||||
imgView.setImageDrawable(drawable);
|
||||
}
|
||||
|
||||
@ -828,12 +839,34 @@ export class Tabs extends TabsBase {
|
||||
tabStripItem.nativeViewProtected.setTypeface(value.getAndroidTypeface());
|
||||
}
|
||||
|
||||
public getTabBarItemTextTransform(tabStripItem: TabStripItem): TextTransform {
|
||||
return this.getItemLabelTextTransform(tabStripItem);
|
||||
}
|
||||
|
||||
public setTabBarItemTextTransform(tabStripItem: TabStripItem, value: TextTransform): void {
|
||||
const nestedLabel = tabStripItem.label;
|
||||
const title = getTransformedText(nestedLabel.text, value);
|
||||
tabStripItem.nativeViewProtected.setText(title);
|
||||
}
|
||||
|
||||
public getTabBarTextTransform(): TextTransform {
|
||||
return this._textTransform;
|
||||
}
|
||||
|
||||
public setTabBarTextTransform(value: TextTransform): void {
|
||||
let items = this.tabStrip && this.tabStrip.items;
|
||||
if (items) {
|
||||
items.forEach((tabStripItem) => {
|
||||
if (tabStripItem.label && tabStripItem.nativeViewProtected) {
|
||||
const nestedLabel = tabStripItem.label;
|
||||
const title = getTransformedText(nestedLabel.text, value);
|
||||
tabStripItem.nativeViewProtected.setText(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
this._textTransform = value;
|
||||
}
|
||||
|
||||
[selectedIndexProperty.setNative](value: number) {
|
||||
const smoothScroll = true;
|
||||
|
||||
|
19
nativescript-core/ui/tabs/tabs.d.ts
vendored
19
nativescript-core/ui/tabs/tabs.d.ts
vendored
@ -49,6 +49,16 @@ export class Tabs extends TabNavigationBase {
|
||||
*/
|
||||
tabsPosition: "top" | "bottom";
|
||||
|
||||
/**
|
||||
* Gets or set the MDCTabBarAlignment of the tab bar icons in iOS. Defaults to "justified"
|
||||
* Valid values are:
|
||||
* - leading
|
||||
* - justified
|
||||
* - center
|
||||
* - centerSelected
|
||||
*/
|
||||
iOSTabBarItemsAlignment: IOSTabBarItemsAlignment;
|
||||
|
||||
/**
|
||||
* Gets the native [android widget](http://developer.android.com/reference/android/support/v4/view/ViewPager.html) that represents the user interface for this component. Valid only when running on Android OS.
|
||||
*/
|
||||
@ -81,3 +91,12 @@ export class Tabs extends TabNavigationBase {
|
||||
export const itemsProperty: Property<Tabs, TabContentItem[]>;
|
||||
export const tabStripProperty: Property<Tabs, TabStrip>
|
||||
export const selectedIndexProperty: Property<Tabs, number>;
|
||||
|
||||
/**
|
||||
* IOS Alignment of the Tabs TabStrip to use.
|
||||
* - `leading` - tab items are aligned to the left
|
||||
* - `justified` - tab strip is split equally to all the tab items
|
||||
* - `center` - tabs items are aligned in the center
|
||||
* - `centerSelected` - tab items move to make the selected tab in the center
|
||||
*/
|
||||
export type IOSTabBarItemsAlignment = "leading" | "justified" | "center" | "centerSelected";
|
||||
|
@ -7,14 +7,15 @@ import { TextTransform, ViewBase } from "../text-base";
|
||||
// Requires
|
||||
import { Color } from "../../color";
|
||||
import { ImageSource } from "../../image-source";
|
||||
import { device } from "../../platform";
|
||||
import { ios as iosUtils, isFontIconURI, layout } from "../../utils/utils";
|
||||
import { ios as iosView, View } from "../core/view";
|
||||
import { Frame } from "../frame";
|
||||
import { Font } from "../styling/font";
|
||||
import {
|
||||
getIconSpecSize, itemsProperty, selectedIndexProperty, tabStripProperty
|
||||
getIconSpecSize, itemsProperty, selectedIndexProperty, tabStripProperty,
|
||||
} from "../tab-navigation-base/tab-navigation-base";
|
||||
import { swipeEnabledProperty, TabsBase } from "./tabs-common";
|
||||
import { swipeEnabledProperty, TabsBase, IOSTabBarItemsAlignment, iOSTabBarItemsAlignmentProperty } from "./tabs-common";
|
||||
|
||||
// TODO
|
||||
// import { profile } from "../../profiling";
|
||||
@ -22,6 +23,7 @@ import { swipeEnabledProperty, TabsBase } from "./tabs-common";
|
||||
export * from "./tabs-common";
|
||||
|
||||
const majorVersion = iosUtils.MajorVersion;
|
||||
const isPhone = device.deviceType === "Phone";
|
||||
|
||||
// Equivalent to dispatch_async(dispatch_get_main_queue(...)) call
|
||||
const invokeOnRunLoop = (function () {
|
||||
@ -74,6 +76,17 @@ class MDCTabBarDelegateImpl extends NSObject implements MDCTabBarDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
class BackgroundIndicatorTemplate extends NSObject implements MDCTabBarIndicatorTemplate {
|
||||
public static ObjCProtocols = [MDCTabBarIndicatorTemplate];
|
||||
|
||||
public indicatorAttributesForContext(context: MDCTabBarIndicatorContext): MDCTabBarIndicatorAttributes {
|
||||
let attributes = new MDCTabBarIndicatorAttributes();
|
||||
attributes.path = UIBezierPath.bezierPathWithRect(context.bounds);
|
||||
|
||||
return attributes;
|
||||
}
|
||||
}
|
||||
|
||||
class UIPageViewControllerImpl extends UIPageViewController {
|
||||
tabBar: MDCTabBar;
|
||||
scrollView: UIScrollView;
|
||||
@ -114,7 +127,7 @@ class UIPageViewControllerImpl extends UIPageViewController {
|
||||
}
|
||||
|
||||
tabBar.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleBottomMargin;
|
||||
tabBar.alignment = MDCTabBarAlignment.Leading;
|
||||
tabBar.alignment = MDCTabBarAlignment.Justified;
|
||||
tabBar.sizeToFit();
|
||||
|
||||
this.tabBar = tabBar;
|
||||
@ -223,6 +236,24 @@ class UIPageViewControllerImpl extends UIPageViewController {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public viewWillTransitionToSizeWithTransitionCoordinator(size: CGSize, coordinator: UIViewControllerTransitionCoordinator): void {
|
||||
super.viewWillTransitionToSizeWithTransitionCoordinator(size, coordinator);
|
||||
coordinator.animateAlongsideTransitionCompletion(() => {
|
||||
const owner = this._owner.get();
|
||||
if (owner && owner.tabStrip && owner.tabStrip.items) {
|
||||
const tabStrip = owner.tabStrip;
|
||||
tabStrip.items.forEach(tabStripItem => {
|
||||
updateBackgroundPositions(tabStrip, tabStripItem,
|
||||
this.tabBar.alignment !== MDCTabBarAlignment.Justified || (owner.selectedIndex !== tabStripItem._index) ? owner._defaultItemBackgroundColor : null);
|
||||
|
||||
const index = tabStripItem._index;
|
||||
const tabBarItemController = owner.viewControllers[index];
|
||||
updateTitleAndIconPositions(tabStripItem, tabBarItemController.tabBarItem, tabBarItemController);
|
||||
});
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
}
|
||||
|
||||
class UIPageViewControllerDataSourceImpl extends NSObject implements UIPageViewControllerDataSource {
|
||||
@ -355,167 +386,6 @@ class UIPageViewControllerDelegateImpl extends NSObject implements UIPageViewCon
|
||||
}
|
||||
}
|
||||
|
||||
// class UITabBarControllerImpl extends UITabBarController {
|
||||
|
||||
// private _owner: WeakRef<Tabs>;
|
||||
|
||||
// public static initWithOwner(owner: WeakRef<Tabs>): UITabBarControllerImpl {
|
||||
// let handler = <UITabBarControllerImpl>UITabBarControllerImpl.new();
|
||||
// handler._owner = owner;
|
||||
// return handler;
|
||||
// }
|
||||
|
||||
// @profile
|
||||
// public viewWillAppear(animated: boolean): void {
|
||||
// super.viewWillAppear(animated);
|
||||
// const owner = this._owner.get();
|
||||
// if (!owner) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // Unify translucent and opaque bars layout
|
||||
// this.extendedLayoutIncludesOpaqueBars = true;
|
||||
|
||||
// iosView.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);
|
||||
// UIViewControllerTransitionCoordinator.prototype.animateAlongsideTransitionCompletion
|
||||
// .call(coordinator, null, () => {
|
||||
// const owner = this._owner.get();
|
||||
// if (owner && owner.items) {
|
||||
// // owner.items.forEach(tabItem => tabItem._updateTitleAndIconPositions()); TODO:
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
|
||||
// class UITabBarControllerDelegateImpl extends NSObject implements UITabBarControllerDelegate {
|
||||
// public static ObjCProtocols = [UITabBarControllerDelegate];
|
||||
|
||||
// private _owner: WeakRef<Tabs>;
|
||||
|
||||
// public static initWithOwner(owner: WeakRef<Tabs>): UITabBarControllerDelegateImpl {
|
||||
// let delegate = <UITabBarControllerDelegateImpl>UITabBarControllerDelegateImpl.new();
|
||||
// delegate._owner = owner;
|
||||
// return delegate;
|
||||
// }
|
||||
|
||||
// public tabBarControllerShouldSelectViewController(tabBarController: UITabBarController, viewController: UIViewController): boolean {
|
||||
// if (traceEnabled()) {
|
||||
// traceWrite("TabView.delegate.SHOULD_select(" + tabBarController + ", " + viewController + ");", traceCategories.Debug);
|
||||
// }
|
||||
|
||||
// let owner = this._owner.get();
|
||||
// if (owner) {
|
||||
// // "< More" cannot be visible after clicking on the main tab bar buttons.
|
||||
// let 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 (traceEnabled()) {
|
||||
// traceWrite("TabView.delegate.DID_select(" + tabBarController + ", " + viewController + ");", traceCategories.Debug);
|
||||
// }
|
||||
|
||||
// const owner = this._owner.get();
|
||||
// if (owner) {
|
||||
// owner._onViewControllerShown(viewController);
|
||||
// }
|
||||
|
||||
// (<any>tabBarController)._willSelectViewController = undefined;
|
||||
// }
|
||||
// }
|
||||
|
||||
// class UINavigationControllerDelegateImpl extends NSObject implements UINavigationControllerDelegate {
|
||||
// public static ObjCProtocols = [UINavigationControllerDelegate];
|
||||
|
||||
// private _owner: WeakRef<Tabs>;
|
||||
|
||||
// public static initWithOwner(owner: WeakRef<Tabs>): UINavigationControllerDelegateImpl {
|
||||
// let delegate = <UINavigationControllerDelegateImpl>UINavigationControllerDelegateImpl.new();
|
||||
// delegate._owner = owner;
|
||||
// return delegate;
|
||||
// }
|
||||
|
||||
// navigationControllerWillShowViewControllerAnimated(navigationController: UINavigationController, viewController: UIViewController, animated: boolean): void {
|
||||
// if (traceEnabled()) {
|
||||
// traceWrite("TabView.moreNavigationController.WILL_show(" + navigationController + ", " + viewController + ", " + animated + ");", traceCategories.Debug);
|
||||
// }
|
||||
|
||||
// let 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.
|
||||
// let backToMoreWillBeVisible = owner._ios.viewControllers.containsObject(viewController);
|
||||
// owner._handleTwoNavigationBars(backToMoreWillBeVisible);
|
||||
// }
|
||||
// }
|
||||
|
||||
// navigationControllerDidShowViewControllerAnimated(navigationController: UINavigationController, viewController: UIViewController, animated: boolean): void {
|
||||
// if (traceEnabled()) {
|
||||
// traceWrite("TabView.moreNavigationController.DID_show(" + navigationController + ", " + viewController + ", " + animated + ");", traceCategories.Debug);
|
||||
// }
|
||||
// // We don't need Edit button in More screen.
|
||||
// navigationController.navigationBar.topItem.rightBarButtonItem = null;
|
||||
// let owner = this._owner.get();
|
||||
// if (owner) {
|
||||
// owner._onViewControllerShown(viewController);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// function updateTitleAndIconPositions(tabStripItem: TabStripItem, tabBarItem: UITabBarItem, controller: UIViewController) {
|
||||
// if (!tabStripItem || !tabBarItem) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // For iOS <11 icon is *always* above the text.
|
||||
// // For iOS 11 icon is above the text *only* on phones in portrait mode.
|
||||
// const orientation = controller.interfaceOrientation;
|
||||
// const isPortrait = orientation !== UIInterfaceOrientation.LandscapeLeft && orientation !== UIInterfaceOrientation.LandscapeRight;
|
||||
// const isIconAboveTitle = (majorVersion < 11) || (isPhone && isPortrait);
|
||||
|
||||
// if (!tabStripItem.iconSource) {
|
||||
// if (isIconAboveTitle) {
|
||||
// tabBarItem.titlePositionAdjustment = { horizontal: 0, vertical: -20 };
|
||||
// } else {
|
||||
// tabBarItem.titlePositionAdjustment = { horizontal: 0, vertical: 0 };
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (!tabStripItem.title) {
|
||||
// if (isIconAboveTitle) {
|
||||
// tabBarItem.imageInsets = new UIEdgeInsets({ top: 6, left: 0, bottom: -6, right: 0 });
|
||||
// } else {
|
||||
// tabBarItem.imageInsets = new UIEdgeInsets({ top: 0, left: 0, bottom: 0, right: 0 });
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
function iterateIndexRange(index: number, eps: number, lastIndex: number, callback: (i) => void) {
|
||||
const rangeStart = Math.max(0, index - eps);
|
||||
const rangeEnd = Math.min(index + eps, lastIndex);
|
||||
@ -524,6 +394,53 @@ function iterateIndexRange(index: number, eps: number, lastIndex: number, callba
|
||||
}
|
||||
}
|
||||
|
||||
function updateBackgroundPositions(tabStrip: TabStrip, tabStripItem: TabStripItem, color: UIColor = null) {
|
||||
let bgView = (<any>tabStripItem).bgView;
|
||||
const index = tabStripItem._index;
|
||||
let width = tabStrip.nativeView.frame.size.width / tabStrip.items.length;
|
||||
const frame = CGRectMake(width * index, 0, width, tabStrip.nativeView.frame.size.width);
|
||||
if (!bgView) {
|
||||
bgView = UIView.alloc().initWithFrame(frame);
|
||||
tabStrip.nativeView.insertSubviewAtIndex(bgView, 0);
|
||||
(<any>tabStripItem).bgView = bgView;
|
||||
}
|
||||
else {
|
||||
bgView.frame = frame;
|
||||
}
|
||||
|
||||
const backgroundColor = tabStripItem.style.backgroundColor;
|
||||
bgView.backgroundColor = color || (backgroundColor instanceof Color ? backgroundColor.ios : backgroundColor);
|
||||
|
||||
}
|
||||
|
||||
function updateTitleAndIconPositions(tabStripItem: TabStripItem, tabBarItem: UITabBarItem, controller: UIViewController) {
|
||||
if (!tabStripItem || !tabBarItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For iOS <11 icon is *always* above the text.
|
||||
// For iOS 11 icon is above the text *only* on phones in portrait mode.
|
||||
const orientation = controller.interfaceOrientation;
|
||||
const isPortrait = orientation !== UIInterfaceOrientation.LandscapeLeft && orientation !== UIInterfaceOrientation.LandscapeRight;
|
||||
const isIconAboveTitle = (majorVersion < 11) || (isPhone && isPortrait);
|
||||
|
||||
if (!tabStripItem.iconSource) {
|
||||
if (isIconAboveTitle) {
|
||||
tabBarItem.titlePositionAdjustment = { horizontal: 0, vertical: -20 };
|
||||
} else {
|
||||
tabBarItem.titlePositionAdjustment = { horizontal: 0, vertical: 0 };
|
||||
}
|
||||
}
|
||||
|
||||
if (!tabStripItem.title) {
|
||||
if (isIconAboveTitle) {
|
||||
tabBarItem.imageInsets = new UIEdgeInsets({ top: 6, left: 0, bottom: -6, right: 0 });
|
||||
} else {
|
||||
tabBarItem.imageInsets = new UIEdgeInsets({ top: 0, left: 0, bottom: 0, right: 0 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Tabs extends TabsBase {
|
||||
public nativeViewProtected: UIView;
|
||||
public selectedIndex: number;
|
||||
@ -542,11 +459,12 @@ export class Tabs extends TabsBase {
|
||||
private _delegate: UIPageViewControllerDelegateImpl;
|
||||
// private _moreNavigationControllerDelegate: UINavigationControllerDelegateImpl;
|
||||
private _iconsCache = {};
|
||||
private _backgroundIndicatorColor: UIColor;
|
||||
public _defaultItemBackgroundColor: UIColor;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// this.viewController = this._ios = <UIPageViewControllerImpl>UIPageViewControllerImpl.initWithOwner(new WeakRef(this)); // .alloc().initWithTransitionStyleNavigationOrientationOptions(UIPageViewControllerTransitionStyle.Scroll, UIPageViewControllerNavigationOrientation.Horizontal, null); // UITabBarControllerImpl.initWithOwner(new WeakRef(this));
|
||||
this.viewController = this._ios = <UIPageViewControllerImpl>UIPageViewControllerImpl.initWithOwner(new WeakRef(this)); //alloc().initWithTransitionStyleNavigationOrientationOptions(UIPageViewControllerTransitionStyle.Scroll, UIPageViewControllerNavigationOrientation.Horizontal, null);;
|
||||
}
|
||||
|
||||
@ -558,8 +476,6 @@ export class Tabs extends TabsBase {
|
||||
super.initNativeView();
|
||||
this._dataSource = UIPageViewControllerDataSourceImpl.initWithOwner(new WeakRef(this));
|
||||
this._delegate = UIPageViewControllerDelegateImpl.initWithOwner(new WeakRef(this));
|
||||
// this._delegate = UITabBarControllerDelegateImpl.initWithOwner(new WeakRef(this));
|
||||
// this._moreNavigationControllerDelegate = UINavigationControllerDelegateImpl.initWithOwner(new WeakRef(this));
|
||||
}
|
||||
|
||||
disposeNativeView() {
|
||||
@ -567,7 +483,6 @@ export class Tabs extends TabsBase {
|
||||
this._delegate = null;
|
||||
this._ios.tabBarDelegate = null;
|
||||
this._ios.tabBar = null;
|
||||
// this._moreNavigationControllerDelegate = null;
|
||||
super.disposeNativeView();
|
||||
}
|
||||
|
||||
@ -576,23 +491,21 @@ export class Tabs extends TabsBase {
|
||||
public onLoaded() {
|
||||
super.onLoaded();
|
||||
|
||||
this.setViewControllers(this.items);
|
||||
|
||||
const selectedIndex = this.selectedIndex;
|
||||
const selectedView = this.items && this.items[selectedIndex] && this.items[selectedIndex].content;
|
||||
if (selectedView instanceof Frame) {
|
||||
(<Frame>selectedView)._pushInFrameStackRecursive();
|
||||
selectedView._pushInFrameStackRecursive();
|
||||
}
|
||||
|
||||
this._ios.dataSource = this._dataSource;
|
||||
this._ios.delegate = this._delegate;
|
||||
|
||||
const tabStripItems = this.tabStrip ? this.tabStrip.items : null;
|
||||
this.setTabStripItems(tabStripItems);
|
||||
}
|
||||
|
||||
public onUnloaded() {
|
||||
this._ios.dataSource = null;
|
||||
this._ios.delegate = null;
|
||||
// this._ios.moreNavigationController.delegate = null;
|
||||
super.onUnloaded();
|
||||
}
|
||||
|
||||
@ -614,20 +527,33 @@ export class Tabs extends TabsBase {
|
||||
return;
|
||||
}
|
||||
|
||||
// const oldItem = items[oldIndex];
|
||||
// if (oldItem) {
|
||||
// oldItem.unloadView(oldItem.view);
|
||||
// }
|
||||
const oldItem = items[oldIndex];
|
||||
if (oldItem) {
|
||||
oldItem.canBeLoaded = false;
|
||||
oldItem.unloadView(oldItem.content);
|
||||
}
|
||||
|
||||
// const newItem = items[newIndex];
|
||||
// if (newItem && this.isLoaded) {
|
||||
// const selectedView = items[newIndex].view;
|
||||
// if (selectedView instanceof Frame) {
|
||||
// selectedView._pushInFrameStackRecursive();
|
||||
// }
|
||||
const newItem = items[newIndex];
|
||||
if (newItem && this.isLoaded) {
|
||||
const selectedView = items[newIndex].content;
|
||||
if (selectedView instanceof Frame) {
|
||||
selectedView._pushInFrameStackRecursive();
|
||||
}
|
||||
|
||||
// newItem.loadView(newItem.view);
|
||||
// }
|
||||
newItem.canBeLoaded = true;
|
||||
newItem.loadView(newItem.content);
|
||||
}
|
||||
|
||||
const tabStripItems = this.tabStrip && this.tabStrip.items;
|
||||
if (tabStripItems) {
|
||||
if (tabStripItems[newIndex]) {
|
||||
tabStripItems[newIndex]._emit(TabStripItem.selectEvent);
|
||||
}
|
||||
|
||||
if (tabStripItems[oldIndex]) {
|
||||
tabStripItems[oldIndex]._emit(TabStripItem.unselectEvent);
|
||||
}
|
||||
}
|
||||
|
||||
this._loadUnloadTabItems(newIndex);
|
||||
|
||||
@ -705,46 +631,6 @@ export class Tabs extends TabsBase {
|
||||
}
|
||||
}
|
||||
|
||||
// private _actionBarHiddenByTabView: boolean;
|
||||
// public _handleTwoNavigationBars(backToMoreWillBeVisible: boolean) {
|
||||
// // TODO
|
||||
// // if (traceEnabled()) {
|
||||
// // traceWrite(`TabView._handleTwoNavigationBars(backToMoreWillBeVisible: ${backToMoreWillBeVisible})`, traceCategories.Debug);
|
||||
// // }
|
||||
|
||||
// // The "< Back" and "< More" navigation bars should not be visible simultaneously.
|
||||
// const page = this.page || this._selectedView.page || (<any>this)._selectedView.currentPage;
|
||||
// if (!page || !page.frame) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// let actionBarVisible = page.frame._getNavBarVisible(page);
|
||||
|
||||
// if (backToMoreWillBeVisible && actionBarVisible) {
|
||||
// page.frame.ios._disableNavBarAnimation = true;
|
||||
// page.actionBarHidden = true;
|
||||
// page.frame.ios._disableNavBarAnimation = false;
|
||||
// this._actionBarHiddenByTabView = true;
|
||||
// // TODO
|
||||
// // if (traceEnabled()) {
|
||||
// // traceWrite(`TabView hid action bar`, traceCategories.Debug);
|
||||
// // }
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (!backToMoreWillBeVisible && this._actionBarHiddenByTabView) {
|
||||
// page.frame.ios._disableNavBarAnimation = true;
|
||||
// page.actionBarHidden = false;
|
||||
// page.frame.ios._disableNavBarAnimation = false;
|
||||
// this._actionBarHiddenByTabView = undefined;
|
||||
// // TODO
|
||||
// // if (traceEnabled()) {
|
||||
// // traceWrite(`TabView restored action bar`, traceCategories.Debug);
|
||||
// // }
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
private getViewController(item: TabContentItem): UIViewController {
|
||||
let newController: UIViewController = item.content ? item.content.viewController : null;
|
||||
|
||||
@ -789,115 +675,57 @@ export class Tabs extends TabsBase {
|
||||
private setViewControllers(items: TabContentItem[]) {
|
||||
const length = items ? items.length : 0;
|
||||
if (length === 0) {
|
||||
// this._ios.setViewControllersDirectionAnimatedCompletion(null, null, false, null);
|
||||
this.viewControllers = null;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const viewControllers = [];
|
||||
const tabBarItems = [];
|
||||
|
||||
items.forEach((item) => {
|
||||
if (this.tabStrip) {
|
||||
this.tabStrip.setNativeView(this._ios.tabBar);
|
||||
}
|
||||
|
||||
const tabStripItems = this.tabStrip && this.tabStrip.items;
|
||||
if (tabStripItems) {
|
||||
if (tabStripItems[this.selectedIndex]) {
|
||||
tabStripItems[this.selectedIndex]._emit(TabStripItem.selectEvent);
|
||||
}
|
||||
}
|
||||
|
||||
items.forEach((item, i) => {
|
||||
const controller = this.getViewController(item);
|
||||
|
||||
if (this.tabStrip && this.tabStrip.items && this.tabStrip.items[i]) {
|
||||
const tabStripItem = <TabStripItem>this.tabStrip.items[i];
|
||||
const tabBarItem = this.createTabBarItem(tabStripItem, i);
|
||||
updateTitleAndIconPositions(tabStripItem, tabBarItem, controller);
|
||||
|
||||
setViewTextAttributes(this._ios.tabBar, tabStripItem.label, i === this.selectedIndex);
|
||||
|
||||
controller.tabBarItem = tabBarItem;
|
||||
tabStripItem._index = i;
|
||||
tabBarItems.push(tabBarItem);
|
||||
tabStripItem.setNativeView(tabBarItem);
|
||||
}
|
||||
|
||||
item.canBeLoaded = true;
|
||||
viewControllers.push(controller);
|
||||
});
|
||||
|
||||
this.viewControllers = viewControllers;
|
||||
|
||||
// const controllers = NSMutableArray.alloc<UIViewController>().initWithCapacity(length);
|
||||
|
||||
// const selectedItem = items[this.selectedIndex];
|
||||
// const controller = this.getViewController(selectedItem);
|
||||
// controllers.addObject(controller);
|
||||
|
||||
// this._ios.setViewControllersDirectionAnimatedCompletion(controllers, UIPageViewControllerNavigationDirection.Forward, false, null);
|
||||
|
||||
iterateIndexRange(this.selectedIndex, 1, this.items.length, (index) => {
|
||||
(<TabContentItem>items[index]).canBeLoaded = true;
|
||||
});
|
||||
|
||||
// (<TabContentItemDefinition>selectedItem).canBeLoaded = true;
|
||||
|
||||
// const nextItem = items[this.selectedIndex + 1];
|
||||
// (<TabContentItemDefinition>nextItem).canBeLoaded = true;
|
||||
|
||||
// const states = getTitleAttributesForStates(this);
|
||||
|
||||
// items.forEach((item, i) => {
|
||||
// const controller = this.getViewController(item);
|
||||
|
||||
// let icon = null;
|
||||
// let title = "";
|
||||
|
||||
// if (this.tabStrip && this.tabStrip.items && this.tabStrip.items[i]) {
|
||||
// const tabStripItem = <TabStripItem>this.tabStrip.items[i];
|
||||
// icon = this._getIcon(tabStripItem.iconSource);
|
||||
// title = tabStripItem.title;
|
||||
|
||||
// const tabBarItem = UITabBarItem.alloc().initWithTitleImageTag((title || ""), icon, i);
|
||||
// updateTitleAndIconPositions(tabStripItem, tabBarItem, controller);
|
||||
|
||||
// applyStatesToItem(tabBarItem, states);
|
||||
|
||||
// controller.tabBarItem = tabBarItem;
|
||||
// }
|
||||
|
||||
// controllers.addObject(controller);
|
||||
// (<TabContentItemDefinition>item).canBeLoaded = true;
|
||||
// });
|
||||
|
||||
// this._ios.viewControllers = controllers;
|
||||
// this._ios.customizableViewControllers = null;
|
||||
|
||||
// // When we set this._ios.viewControllers, someone is clearing the moreNavigationController.delegate, so we have to reassign it each time here.
|
||||
// this._ios.moreNavigationController.delegate = this._moreNavigationControllerDelegate;
|
||||
}
|
||||
|
||||
private setTabStripItems(items: Array<TabStripItem>) {
|
||||
if (!this.tabStrip || !items) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tabBarItems = [];
|
||||
|
||||
items.forEach((tabStripItem: TabStripItem, i) => {
|
||||
tabStripItem._index = i;
|
||||
const tabBarItem = this.createTabBarItem(tabStripItem, i);
|
||||
tabBarItems.push(tabBarItem);
|
||||
tabStripItem.setNativeView(tabBarItem);
|
||||
});
|
||||
|
||||
this.tabBarItems = tabBarItems;
|
||||
|
||||
if (this.viewController && this.viewController.tabBar) {
|
||||
this.viewController.tabBar.itemAppearance = this.getTabBarItemAppearance();
|
||||
this.viewController.tabBar.items = NSArray.arrayWithArray(tabBarItems);
|
||||
this.viewController.tabBar.items = NSArray.arrayWithArray(this.tabBarItems);
|
||||
// TODO: investigate why this call is necessary to actually toggle item appearance
|
||||
this.viewController.tabBar.sizeToFit();
|
||||
this.tabStrip.setNativeView(this.viewController.tabBar);
|
||||
if (this.selectedIndex) {
|
||||
this.viewController.tabBar.setSelectedItemAnimated(this.tabBarItems[this.selectedIndex], false);
|
||||
}
|
||||
}
|
||||
|
||||
// const length = items ? items.length : 0;
|
||||
// if (length === 0) {
|
||||
// this._tabLayout.setItems(null, null);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// const tabItems = new Array<org.nativescript.widgets.TabItemSpec>();
|
||||
// items.forEach((item: TabStripItem, i, arr) => {
|
||||
// const tabItemSpec = createTabItemSpec(item);
|
||||
// (<any>item).index = i;
|
||||
// (<any>item).tabItemSpec = tabItemSpec;
|
||||
// tabItems.push(tabItemSpec);
|
||||
// });
|
||||
|
||||
// const tabLayout = this._tabLayout;
|
||||
// tabLayout.setItems(tabItems, this._viewPager);
|
||||
// items.forEach((item, i, arr) => {
|
||||
// const tv = tabLayout.getTextViewForItemAt(i);
|
||||
// item.setNativeView(tv);
|
||||
// });
|
||||
}
|
||||
|
||||
private createTabBarItem(item: TabStripItem, index: number): UITabBarItem {
|
||||
@ -924,9 +752,9 @@ export class Tabs extends TabsBase {
|
||||
|
||||
private getTabBarItemAppearance(): MDCTabBarItemAppearance {
|
||||
let itemAppearance;
|
||||
if (this.tabStrip._hasImage && this.tabStrip._hasTitle) {
|
||||
if (this.tabStrip && this.tabStrip._hasImage && this.tabStrip._hasTitle) {
|
||||
itemAppearance = MDCTabBarItemAppearance.TitledImages;
|
||||
} else if (this.tabStrip._hasImage) {
|
||||
} else if (this.tabStrip && this.tabStrip._hasImage) {
|
||||
itemAppearance = MDCTabBarItemAppearance.Images;
|
||||
} else {
|
||||
itemAppearance = MDCTabBarItemAppearance.Titles;
|
||||
@ -941,6 +769,8 @@ export class Tabs extends TabsBase {
|
||||
}
|
||||
|
||||
private getIcon(tabStripItem: TabStripItem): UIImage {
|
||||
// Image and Label children of TabStripItem
|
||||
// take priority over its `iconSource` and `title` properties
|
||||
const iconSource = tabStripItem.image && tabStripItem.image.src;
|
||||
if (!iconSource) {
|
||||
return null;
|
||||
@ -948,13 +778,15 @@ export class Tabs extends TabsBase {
|
||||
|
||||
const target = tabStripItem.image;
|
||||
const font = target.style.fontInternal;
|
||||
const color = tabStripItem.parent.style.color;
|
||||
const color = target.style.color;
|
||||
const iconTag = [iconSource, font.fontStyle, font.fontWeight, font.fontSize, font.fontFamily, color].join(";");
|
||||
|
||||
let isFontIcon = false;
|
||||
let image: UIImage = this._iconsCache[iconTag];
|
||||
if (!image) {
|
||||
let is = new ImageSource;
|
||||
if (isFontIconURI(iconSource)) {
|
||||
isFontIcon = true;
|
||||
const fontIconCode = iconSource.split("//")[1];
|
||||
is = ImageSource.fromFontIconCodeSync(fontIconCode, font, color);
|
||||
} else {
|
||||
@ -968,7 +800,11 @@ export class Tabs extends TabsBase {
|
||||
image = this.getFixedSizeIcon(image);
|
||||
}
|
||||
|
||||
const originalRenderedImage = image.imageWithRenderingMode(this.getIconRenderingMode());
|
||||
let renderingMode: UIImageRenderingMode = UIImageRenderingMode.AlwaysOriginal;
|
||||
if (!isFontIcon) {
|
||||
renderingMode = this.getIconRenderingMode();
|
||||
}
|
||||
const originalRenderedImage = image.imageWithRenderingMode(renderingMode);
|
||||
this._iconsCache[iconTag] = originalRenderedImage;
|
||||
image = originalRenderedImage;
|
||||
} else {
|
||||
@ -997,26 +833,6 @@ export class Tabs extends TabsBase {
|
||||
return resultImage;
|
||||
}
|
||||
|
||||
// private _updateIOSTabBarColorsAndFonts(): void {
|
||||
// if (!this.tabStrip || !this.tabStrip.items || !this.tabStrip.items.length) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// const tabBar = <UITabBar>this.ios.tabBar;
|
||||
// const states = getTitleAttributesForStates(this);
|
||||
// for (let i = 0; i < tabBar.items.count; i++) {
|
||||
// applyStatesToItem(tabBar.items[i], states);
|
||||
// }
|
||||
// }
|
||||
|
||||
// TODO: Move this to TabStripItem
|
||||
// [fontInternalProperty.getDefault](): Font {
|
||||
// return null;
|
||||
// }
|
||||
// [fontInternalProperty.setNative](value: Font) {
|
||||
// this._updateIOSTabBarColorsAndFonts();
|
||||
// }
|
||||
|
||||
public getTabBarBackgroundColor(): UIColor {
|
||||
return this._ios.tabBar.barTintColor;
|
||||
}
|
||||
@ -1025,6 +841,69 @@ export class Tabs extends TabsBase {
|
||||
this._ios.tabBar.barTintColor = value instanceof Color ? value.ios : value;
|
||||
}
|
||||
|
||||
public setTabBarItemTitle(tabStripItem: TabStripItem, value: string): void {
|
||||
tabStripItem.nativeView.title = value;
|
||||
}
|
||||
|
||||
private equalUIColor(first: UIColor, second: UIColor): boolean {
|
||||
if (!first && !second) {
|
||||
return true;
|
||||
}
|
||||
if (!first || !second) {
|
||||
return false;
|
||||
}
|
||||
const firstComponents = CGColorGetComponents(first.CGColor);
|
||||
const secondComponents = CGColorGetComponents(second.CGColor);
|
||||
|
||||
return firstComponents[0] === secondComponents[0]
|
||||
&& firstComponents[1] === secondComponents[1]
|
||||
&& firstComponents[2] === secondComponents[2]
|
||||
&& firstComponents[3] === secondComponents[3];
|
||||
}
|
||||
|
||||
private isSelectedAndHightlightedItem(tabStripItem: TabStripItem): boolean {
|
||||
return (tabStripItem._index === this.selectedIndex && tabStripItem["_visualState"] === "highlighted");
|
||||
}
|
||||
|
||||
public setTabBarItemBackgroundColor(tabStripItem: TabStripItem, value: UIColor | Color): void {
|
||||
if (!this.tabStrip || !tabStripItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
let newColor = value instanceof Color ? value.ios : value;
|
||||
const itemSelectedAndHighlighted = this.isSelectedAndHightlightedItem(tabStripItem);
|
||||
|
||||
if (!this._defaultItemBackgroundColor && !itemSelectedAndHighlighted) {
|
||||
this._defaultItemBackgroundColor = newColor;
|
||||
}
|
||||
|
||||
if (this.viewController.tabBar.alignment !== MDCTabBarAlignment.Justified && itemSelectedAndHighlighted
|
||||
&& !this.equalUIColor(this._defaultItemBackgroundColor, newColor)) {
|
||||
if (!this._backgroundIndicatorColor) {
|
||||
this._backgroundIndicatorColor = newColor;
|
||||
this._ios.tabBar.selectionIndicatorTemplate = new BackgroundIndicatorTemplate();
|
||||
this._ios.tabBar.tintColor = newColor;
|
||||
}
|
||||
} else {
|
||||
updateBackgroundPositions(this.tabStrip, tabStripItem, newColor);
|
||||
}
|
||||
}
|
||||
|
||||
public setTabBarItemColor(tabStripItem: TabStripItem, value: UIColor | Color): void {
|
||||
setViewTextAttributes(this._ios.tabBar, tabStripItem.label);
|
||||
}
|
||||
|
||||
public setTabBarIconColor(tabStripItem: TabStripItem, value: UIColor | Color): void {
|
||||
const image = this.getIcon(tabStripItem);
|
||||
|
||||
tabStripItem.nativeView.image = image;
|
||||
tabStripItem.nativeView.selectedImage = image;
|
||||
}
|
||||
|
||||
public setTabBarItemFontInternal(tabStripItem: TabStripItem, value: Font): void {
|
||||
setViewTextAttributes(this._ios.tabBar, tabStripItem.label);
|
||||
}
|
||||
|
||||
public getTabBarFontInternal(): UIFont {
|
||||
return this._ios.tabBar.unselectedItemTitleFont;
|
||||
}
|
||||
@ -1039,7 +918,15 @@ export class Tabs extends TabsBase {
|
||||
}
|
||||
|
||||
public getTabBarTextTransform(): TextTransform {
|
||||
return null;
|
||||
switch (this._ios.tabBar.titleTextTransform) {
|
||||
case MDCTabBarTextTransform.None:
|
||||
return "none";
|
||||
case MDCTabBarTextTransform.Automatic:
|
||||
return "initial";
|
||||
case MDCTabBarTextTransform.Uppercase:
|
||||
default:
|
||||
return "uppercase";
|
||||
}
|
||||
}
|
||||
|
||||
public setTabBarTextTransform(value: TextTransform): void {
|
||||
@ -1047,11 +934,13 @@ export class Tabs extends TabsBase {
|
||||
this._ios.tabBar.titleTextTransform = MDCTabBarTextTransform.None;
|
||||
} else if (value === "uppercase") {
|
||||
this._ios.tabBar.titleTextTransform = MDCTabBarTextTransform.Uppercase;
|
||||
} else if (value === "initial") {
|
||||
this._ios.tabBar.titleTextTransform = MDCTabBarTextTransform.Automatic;
|
||||
}
|
||||
}
|
||||
|
||||
public getTabBarColor(): UIColor {
|
||||
return this._ios.tabBar.titleColorForState(MDCTabBarItemState.Normal);
|
||||
return this._ios.tabBar.titleColorForState(MDCTabBarItemState.Normal);
|
||||
}
|
||||
|
||||
public setTabBarColor(value: UIColor | Color): void {
|
||||
@ -1134,6 +1023,12 @@ export class Tabs extends TabsBase {
|
||||
return null;
|
||||
}
|
||||
[itemsProperty.setNative](value: TabContentItem[]) {
|
||||
if (value) {
|
||||
value.forEach((item: TabContentItem, i) => {
|
||||
(<any>item).index = i;
|
||||
});
|
||||
}
|
||||
|
||||
this.setViewControllers(value);
|
||||
selectedIndexProperty.coerce(this);
|
||||
}
|
||||
@ -1141,16 +1036,74 @@ export class Tabs extends TabsBase {
|
||||
[tabStripProperty.getDefault](): TabStrip {
|
||||
return null;
|
||||
}
|
||||
|
||||
[tabStripProperty.setNative](value: TabStrip) {
|
||||
this.setTabStripItems(value.items);
|
||||
this.setViewControllers(this.items);
|
||||
selectedIndexProperty.coerce(this);
|
||||
}
|
||||
|
||||
[swipeEnabledProperty.getDefault](): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
[swipeEnabledProperty.setNative](value: boolean) {
|
||||
if (this.viewController && this.viewController.scrollView) {
|
||||
this.viewController.scrollView.scrollEnabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
[iOSTabBarItemsAlignmentProperty.getDefault](): IOSTabBarItemsAlignment {
|
||||
if (!this.viewController || !this.viewController.tabBar) {
|
||||
return "justified";
|
||||
}
|
||||
|
||||
let alignment = this.viewController.tabBar.alignment.toString();
|
||||
|
||||
return <any>(alignment.charAt(0).toLowerCase() + alignment.substring(1));
|
||||
}
|
||||
|
||||
[iOSTabBarItemsAlignmentProperty.setNative](value: IOSTabBarItemsAlignment) {
|
||||
if (!this.viewController || !this.viewController.tabBar) {
|
||||
return;
|
||||
}
|
||||
|
||||
let alignment = MDCTabBarAlignment.Justified;
|
||||
switch (value) {
|
||||
case "leading":
|
||||
alignment = MDCTabBarAlignment.Leading;
|
||||
break;
|
||||
case "center":
|
||||
alignment = MDCTabBarAlignment.Center;
|
||||
break;
|
||||
case "centerSelected":
|
||||
alignment = MDCTabBarAlignment.CenterSelected;
|
||||
break;
|
||||
}
|
||||
|
||||
this.viewController.tabBar.alignment = alignment;
|
||||
}
|
||||
}
|
||||
|
||||
function setViewTextAttributes(tabBar: MDCTabBar, view: View, setSelected: boolean = false): any {
|
||||
if (!view) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const defaultTabItemFontSize = 10;
|
||||
const tabItemFontSize = view.style.fontSize || defaultTabItemFontSize;
|
||||
const font: UIFont = view.style.fontInternal.getUIFont(UIFont.systemFontOfSize(tabItemFontSize));
|
||||
|
||||
tabBar.unselectedItemTitleFont = font;
|
||||
tabBar.selectedItemTitleFont = font;
|
||||
|
||||
const tabItemTextColor = view.style.color;
|
||||
const textColor = tabItemTextColor instanceof Color ? tabItemTextColor.ios : null;
|
||||
if (textColor) {
|
||||
tabBar.setTitleColorForState(textColor, MDCTabBarItemState.Normal);
|
||||
if (setSelected) {
|
||||
tabBar.setTitleColorForState(textColor, MDCTabBarItemState.Selected);
|
||||
}
|
||||
}
|
||||
|
||||
tabBar.inkColor = UIColor.clearColor;
|
||||
}
|
Reference in New Issue
Block a user