Merge branch 'master' into fix_css_styles

This commit is contained in:
Dimitar Topuzov
2020-03-10 16:09:14 +02:00
committed by GitHub
22 changed files with 560 additions and 474 deletions

View File

@ -0,0 +1 @@
export declare function cssTreeParse(css: any, source: any): any;

View File

@ -14,6 +14,7 @@
"Foundation.*:*",
"MaterialComponents.MDCTabBar:*",
"MaterialComponents.MDCTabBarIndicatorTemplate:*",
"NativeScriptEmbedder:*",

View File

@ -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;

View File

@ -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;

View File

@ -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];
}
}
}

View File

@ -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;
}

View File

@ -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)));

View File

@ -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.

View File

@ -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";

View File

@ -286,4 +286,4 @@ export const tabStripProperty = new Property<TabNavigationBase, TabStrip>({
target.onTabStripChanged(oldValue, newValue);
}
});
tabStripProperty.register(TabNavigationBase);
tabStripProperty.register(TabNavigationBase);

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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";

View File

@ -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;
}