Merge branch 'master' into myankov/ios10-tabs

This commit is contained in:
Svetoslav
2019-08-16 10:53:45 +03:00
committed by GitHub
45 changed files with 837 additions and 458 deletions

View File

@@ -85,7 +85,7 @@ function initializeNativeClasses() {
public onCreateView(inflater: android.view.LayoutInflater, container: android.view.ViewGroup, savedInstanceState: android.os.Bundle): android.view.View {
const tabItem = this.tab.items[this.index];
return tabItem.view.nativeViewProtected;
return tabItem.nativeViewProtected;
}
}
@@ -167,43 +167,58 @@ function initializeNativeClasses() {
}
function createTabItemSpec(tabStripItem: TabStripItem): org.nativescript.widgets.TabItemSpec {
let iconSource;
const tabItemSpec = new org.nativescript.widgets.TabItemSpec();
// Image and Label children of TabStripItem
// take priority over its `iconSource` and `title` properties
iconSource = tabStripItem.image ? tabStripItem.image.src : tabStripItem.iconSource;
tabItemSpec.title = tabStripItem.label ? tabStripItem.label.text : tabStripItem.title;
if (tabStripItem.isLoaded) {
const titleLabel = tabStripItem.label;
let title = titleLabel.text;
if (tabStripItem.backgroundColor instanceof Color) {
tabItemSpec.backgroundColor = tabStripItem.backgroundColor.android;
}
// TEXT-TRANSFORM
const textTransform = titleLabel.style.textTransform;
if (textTransform) {
title = getTransformedText(title, textTransform);
}
tabItemSpec.title = title;
if (iconSource) {
if (iconSource.indexOf(RESOURCE_PREFIX) === 0) {
tabItemSpec.iconId = ad.resources.getDrawableId(iconSource.substr(RESOURCE_PREFIX.length));
if (tabItemSpec.iconId === 0) {
// TODO:
// traceMissingIcon(iconSource);
}
} else {
let is = new ImageSource();
if (isFontIconURI(tabStripItem.iconSource)) {
const fontIconCode = tabStripItem.iconSource.split("//")[1];
const font = tabStripItem.style.fontInternal;
const color = tabStripItem.style.color;
is = fromFontIconCode(fontIconCode, font, color);
// BACKGROUND-COLOR
const backgroundColor = tabStripItem.style.backgroundColor;
if (backgroundColor) {
tabItemSpec.backgroundColor = backgroundColor.android;
}
// COLOR
const color = titleLabel.style.color;
if (color) {
tabItemSpec.color = color.android;
}
// FONT
const fontInternal = titleLabel.style.fontInternal;
if (fontInternal) {
tabItemSpec.fontSize = fontInternal.fontSize;
tabItemSpec.typeFace = fontInternal.getAndroidTypeface();
}
// ICON
const iconSource = tabStripItem.image && tabStripItem.image.src;
if (iconSource) {
if (iconSource.indexOf(RESOURCE_PREFIX) === 0) {
tabItemSpec.iconId = ad.resources.getDrawableId(iconSource.substr(RESOURCE_PREFIX.length));
if (tabItemSpec.iconId === 0) {
// TODO:
// traceMissingIcon(iconSource);
}
} else {
is = fromFileOrResource(tabStripItem.iconSource);
}
const icon = _getIcon(tabStripItem);
if (is) {
// TODO: Make this native call that accepts string so that we don't load Bitmap in JS.
// tslint:disable-next-line:deprecation
tabItemSpec.iconDrawable = new android.graphics.drawable.BitmapDrawable(application.android.context.getResources(), is.android);
} else {
// TODO:
// traceMissingIcon(iconSource);
if (icon) {
// 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;
} else {
// TODO:
// traceMissingIcon(iconSource);
}
}
}
}
@@ -211,11 +226,29 @@ function createTabItemSpec(tabStripItem: TabStripItem): org.nativescript.widgets
return tabItemSpec;
}
function setElevation(grid: org.nativescript.widgets.GridLayout, bottomNavigationBar: org.nativescript.widgets.BottomNavigationBar) {
function _getIcon(tabStripItem: TabStripItem): android.graphics.drawable.BitmapDrawable {
const iconSource = tabStripItem.image && tabStripItem.image.src;
let is: ImageSource;
if (isFontIconURI(iconSource)) {
const fontIconCode = iconSource.split("//")[1];
const target = tabStripItem.image ? tabStripItem.image : tabStripItem;
const font = target.style.fontInternal;
const color = target.style.color;
is = fromFontIconCode(fontIconCode, font, color);
} else {
is = fromFileOrResource(iconSource);
}
const image = new android.graphics.drawable.BitmapDrawable(application.android.context.getResources(), is.android);
return image;
}
function setElevation(bottomNavigationBar: org.nativescript.widgets.BottomNavigationBar) {
const compat = <any>androidx.core.view.ViewCompat;
if (compat.setElevation) {
const val = DEFAULT_ELEVATION * layout.getDisplayDensity();
compat.setElevation(grid, val);
compat.setElevation(bottomNavigationBar, val);
}
}
@@ -288,7 +321,7 @@ export class BottomNavigation extends TabNavigationBase {
nativeView.addView(bottomNavigationBar);
(<any>nativeView).bottomNavigationBar = bottomNavigationBar;
setElevation(nativeView, bottomNavigationBar);
setElevation(bottomNavigationBar);
const primaryColor = ad.resources.getPaletteColor(PRIMARY_COLOR, context);
if (primaryColor) {
@@ -341,12 +374,12 @@ export class BottomNavigation extends TabNavigationBase {
toUnload.forEach(index => {
const item = items[index];
if (items[index]) {
item.unloadView(item.view);
item.unloadView(item.content);
}
});
const newItem = items[newIndex];
const selectedView = newItem && newItem.view;
const selectedView = newItem && newItem.content;
if (selectedView instanceof Frame) {
selectedView._pushInFrameStackRecursive();
}
@@ -354,7 +387,7 @@ export class BottomNavigation extends TabNavigationBase {
toLoad.forEach(index => {
const item = items[index];
if (this.isLoaded && items[index]) {
item.loadView(item.view);
item.loadView(item.content);
}
});
}
@@ -562,18 +595,11 @@ export class BottomNavigation extends TabNavigationBase {
}
}
public getTabBarColor(): number {
return this._bottomNavigationBar.getTabTextColor();
}
public setTabBarColor(value: number | Color): void {
if (value instanceof Color) {
this._bottomNavigationBar.setTabTextColor(value.android);
this._bottomNavigationBar.setSelectedTabTextColor(value.android);
} else {
this._bottomNavigationBar.setTabTextColor(value);
this._bottomNavigationBar.setSelectedTabTextColor(value);
}
public setTabBarItemTitle(tabStripItem: TabStripItem, value: string): void {
// TODO: Should figure out a way to do it directly with the the nativeView
const tabStripItemIndex = this.tabStrip.items.indexOf(tabStripItem);
const tabItemSpec = createTabItemSpec(tabStripItem);
this.updateAndroidItemAt(tabStripItemIndex, tabItemSpec);
}
public setTabBarItemBackgroundColor(tabStripItem: TabStripItem, value: android.graphics.drawable.Drawable | Color): void {
@@ -583,10 +609,6 @@ export class BottomNavigation extends TabNavigationBase {
this.updateAndroidItemAt(tabStripItemIndex, tabItemSpec);
}
public getTabBarItemColor(tabStripItem: TabStripItem): number {
return tabStripItem.nativeViewProtected.getCurrentTextColor();
}
public setTabBarItemColor(tabStripItem: TabStripItem, value: number | Color): void {
if (typeof value === "number") {
tabStripItem.nativeViewProtected.setTextColor(value);
@@ -595,45 +617,24 @@ export class BottomNavigation extends TabNavigationBase {
}
}
public getTabBarItemFontSize(tabStripItem: TabStripItem): { nativeSize: number } {
return { nativeSize: tabStripItem.nativeViewProtected.getTextSize() };
public setTabBarIconColor(tabStripItem: TabStripItem, value: number | Color): void {
const index = (<any>tabStripItem).index;
const tabBarItem = this._bottomNavigationBar.getViewForItemAt(index);
const imgView = <android.widget.ImageView>tabBarItem.getChildAt(0);
const drawable = _getIcon(tabStripItem);
imgView.setImageDrawable(drawable);
}
public setTabBarItemFontSize(tabStripItem: TabStripItem, value: number | { nativeSize: number }): void {
if (typeof value === "number") {
tabStripItem.nativeViewProtected.setTextSize(value);
} else {
tabStripItem.nativeViewProtected.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, value.nativeSize);
}
public setTabBarItemFontInternal(tabStripItem: TabStripItem, value: Font): void {
tabStripItem.nativeViewProtected.setTextSize(value.fontSize);
tabStripItem.nativeViewProtected.setTypeface(value.getAndroidTypeface());
}
public getTabBarItemFontInternal(tabStripItem: TabStripItem): android.graphics.Typeface {
return tabStripItem.nativeViewProtected.getTypeface();
}
public setTabBarItemFontInternal(tabStripItem: TabStripItem, value: Font | android.graphics.Typeface): void {
tabStripItem.nativeViewProtected.setTypeface(value instanceof Font ? value.getAndroidTypeface() : value);
}
private _defaultTransformationMethod: android.text.method.TransformationMethod;
public getTabBarItemTextTransform(tabStripItem: TabStripItem): "default" {
return "default";
}
public setTabBarItemTextTransform(tabStripItem: TabStripItem, value: TextTransform | "default"): void {
const tv = tabStripItem.nativeViewProtected;
this._defaultTransformationMethod = this._defaultTransformationMethod || tv.getTransformationMethod();
if (value === "default") {
tv.setTransformationMethod(this._defaultTransformationMethod);
tv.setText(tabStripItem.title);
} else {
const result = getTransformedText(tabStripItem.title, value);
tv.setText(result);
tv.setTransformationMethod(null);
}
public setTabBarItemTextTransform(tabStripItem: TabStripItem, value: TextTransform): void {
const titleLabel = tabStripItem.label;
const title = getTransformedText(titleLabel.text, value);
tabStripItem.nativeViewProtected.setText(title);
}
[selectedIndexProperty.setNative](value: number) {

View File

@@ -259,8 +259,10 @@ export class BottomNavigation extends TabNavigationBase {
public onLoaded() {
super.onLoaded();
this.setViewControllers(this.items);
const selectedIndex = this.selectedIndex;
const selectedView = this.items && this.items[selectedIndex] && this.items[selectedIndex].view;
const selectedView = this.items && this.items[selectedIndex] && this.items[selectedIndex].content;
if (selectedView instanceof Frame) {
selectedView._pushInFrameStackRecursive();
}
@@ -295,18 +297,18 @@ export class BottomNavigation extends TabNavigationBase {
const oldItem = items[oldIndex];
if (oldItem) {
oldItem.canBeLoaded = false;
oldItem.unloadView(oldItem.view);
oldItem.unloadView(oldItem.content);
}
const newItem = items[newIndex];
if (newItem && this.isLoaded) {
const selectedView = items[newIndex].view;
const selectedView = items[newIndex].content;
if (selectedView instanceof Frame) {
selectedView._pushInFrameStackRecursive();
}
newItem.canBeLoaded = true;
newItem.loadView(newItem.view);
newItem.loadView(newItem.content);
}
super.onSelectedIndexChanged(oldIndex, newIndex);
@@ -320,21 +322,8 @@ export class BottomNavigation extends TabNavigationBase {
this._ios.tabBar.barTintColor = value instanceof Color ? value.ios : value;
}
public getTabBarColor(): UIColor {
return this._ios.tabBar.tintColor;
}
public setTabBarColor(value: UIColor | Color): void {
this._ios.tabBar.tintColor = value instanceof Color ? value.ios : value;
if (!this.tabStrip) {
return;
}
const states = getTitleAttributesForStates(this.tabStrip);
this.tabStrip.items.forEach((tabStripItem) => {
applyStatesToItem(tabStripItem.nativeView, states);
});
public setTabBarItemTitle(tabStripItem: TabStripItem, value: string): void {
tabStripItem.nativeView.title = value;
}
public setTabBarItemBackgroundColor(tabStripItem: TabStripItem, value: UIColor | Color): void {
@@ -355,39 +344,25 @@ export class BottomNavigation extends TabNavigationBase {
bgView.backgroundColor = value instanceof Color ? value.ios : value;
}
public getTabBarItemColor(tabStripItem: TabStripItem): UIColor {
return this._ios.tabBar.tintColor;
}
public setTabBarItemColor(tabStripItem: TabStripItem, value: UIColor | Color): void {
const states = getTitleAttributesForStates(tabStripItem);
const states = getTitleAttributesForStates(tabStripItem.label);
applyStatesToItem(tabStripItem.nativeView, states);
}
public getTabBarItemFontSize(tabStripItem: TabStripItem): number {
return null;
}
public setTabBarIconColor(tabStripItem: TabStripItem, value: UIColor | Color): void {
const image = this._getIcon(tabStripItem);
public setTabBarItemFontSize(tabStripItem: TabStripItem, value: number | { nativeSize: number }): void {
const states = getTitleAttributesForStates(tabStripItem);
applyStatesToItem(tabStripItem.nativeView, states);
}
public getTabBarItemFontInternal(tabStripItem: TabStripItem): Font {
return null;
tabStripItem.nativeView.image = image;
tabStripItem.nativeView.selectedImage = image;
}
public setTabBarItemFontInternal(tabStripItem: TabStripItem, value: Font): void {
const states = getTitleAttributesForStates(tabStripItem);
const states = getTitleAttributesForStates(tabStripItem.label);
applyStatesToItem(tabStripItem.nativeView, states);
}
public getTabBarItemTextTransform(tabStripItem: TabStripItem): TextTransform {
return null;
}
public setTabBarItemTextTransform(tabStripItem: TabStripItem, value: TextTransform): void {
const title = getTransformedText(tabStripItem.title, value);
const title = getTransformedText(tabStripItem.label.text, value);
tabStripItem.nativeView.title = title;
}
@@ -463,7 +438,7 @@ export class BottomNavigation extends TabNavigationBase {
}
private getViewController(item: TabContentItem): UIViewController {
let newController: UIViewController = item.view ? item.view.viewController : null;
let newController: UIViewController = item.content ? item.content.viewController : null;
if (newController) {
(<any>item).setViewController(newController, newController.view);
@@ -471,17 +446,17 @@ export class BottomNavigation extends TabNavigationBase {
return newController;
}
if (item.view.ios instanceof UIViewController) {
newController = item.view.ios;
if (item.content.ios instanceof UIViewController) {
newController = item.content.ios;
(<any>item).setViewController(newController, newController.view);
} else if (item.view.ios && item.view.ios.controller instanceof UIViewController) {
newController = item.view.ios.controller;
} else if (item.content.ios && item.content.ios.controller instanceof UIViewController) {
newController = item.content.ios.controller;
(<any>item).setViewController(newController, newController.view);
} else {
newController = iosView.UILayoutViewController.initWithOwner(new WeakRef(item.view)) as UIViewController;
newController.view.addSubview(item.view.nativeViewProtected);
item.view.viewController = newController;
(<any>item).setViewController(newController, item.view.nativeViewProtected);
newController = iosView.UILayoutViewController.initWithOwner(new WeakRef(item.content)) as UIViewController;
newController.view.addSubview(item.content.nativeViewProtected);
item.content.viewController = newController;
(<any>item).setViewController(newController, item.content.nativeViewProtected);
}
return newController;
@@ -499,7 +474,6 @@ export class BottomNavigation extends TabNavigationBase {
items = items.slice(0, maxTabsCount);
const controllers = NSMutableArray.alloc<UIViewController>().initWithCapacity(length);
const states = getTitleAttributesForStates(this);
if (this.tabStrip) {
this.tabStrip.setNativeView(this._ios.tabBar);
@@ -513,6 +487,7 @@ export class BottomNavigation extends TabNavigationBase {
const tabBarItem = this.createTabBarItem(tabStripItem, i);
updateTitleAndIconPositions(tabStripItem, tabBarItem, controller);
const states = getTitleAttributesForStates(tabStripItem.label);
applyStatesToItem(tabBarItem, states);
controller.tabBarItem = tabBarItem;
@@ -534,8 +509,15 @@ export class BottomNavigation extends TabNavigationBase {
let image: UIImage;
let title: string;
image = this._getIcon(item);
title = item.label ? item.label.text : item.title;
if (item.isLoaded) {
image = this._getIcon(item);
title = item.label.text;
const textTransform = item.label.style.textTransform;
if (textTransform) {
title = getTransformedText(title, textTransform);
}
}
const tabBarItem = UITabBarItem.alloc().initWithTitleImageTag(title, image, index);
@@ -549,18 +531,21 @@ export class BottomNavigation extends TabNavigationBase {
public _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 : tabStripItem.iconSource;
const iconSource = tabStripItem.image && tabStripItem.image.src;
if (!iconSource) {
return null;
}
let image: UIImage = this._iconsCache[iconSource];
const target = tabStripItem.image;
const font = target.style.fontInternal;
const color = target.style.color;
const iconTag = [iconSource, font.fontStyle, font.fontWeight, font.fontSize, font.fontFamily, color].join(";");
let image: UIImage = this._iconsCache[iconTag];
if (!image) {
let is = new ImageSource;
if (isFontIconURI(iconSource)) {
const fontIconCode = iconSource.split("//")[1];
const font = tabStripItem.style.fontInternal;
const color = tabStripItem.style.color;
is = fromFontIconCode(fontIconCode, font, color);
} else {
is = fromFileOrResource(iconSource);
@@ -568,7 +553,7 @@ export class BottomNavigation extends TabNavigationBase {
if (is && is.ios) {
const originalRenderedImage = is.ios.imageWithRenderingMode(this._getIconRenderingMode());
this._iconsCache[iconSource] = originalRenderedImage;
this._iconsCache[iconTag] = originalRenderedImage;
image = originalRenderedImage;
} else {
// TODO
@@ -615,6 +600,12 @@ export class BottomNavigation extends TabNavigationBase {
return null;
}
[itemsProperty.setNative](value: TabContentItem[]) {
if (value) {
value.forEach((item: TabContentItem, i) => {
(<any>item).index = i;
});
}
this.setViewControllers(value);
selectedIndexProperty.coerce(this);
}

View File

@@ -5,38 +5,15 @@ import { TabNavigationBase } from "../tab-navigation-base";
// Requires
import { View, ViewBase, CSSType } from "../../core/view";
import { ContentView } from "../../content-view";
export const traceCategory = "TabView";
@CSSType("TabContentItem")
export abstract class TabContentItemBase extends ViewBase implements TabContentItemDefinition, AddChildFromBuilder {
private _view: View;
export abstract class TabContentItemBase extends ContentView implements TabContentItemDefinition, AddChildFromBuilder {
public _addChildFromBuilder(name: string, value: any): void {
if (value instanceof View) {
this.view = value;
}
}
// TODO: Should we rename this to content? Or even better - inherit ContentView???
get view(): View {
return this._view;
}
set view(value: View) {
if (this._view !== value) {
if (this._view) {
throw new Error("Changing the view of an already loaded TabContentItem is not currently supported.");
}
this._view = value;
this._addView(value);
}
}
public eachChild(callback: (child: ViewBase) => boolean) {
const view = this._view;
if (view) {
callback(view);
public eachChild(callback: (child: View) => boolean) {
if (this.content) {
callback(this.content);
}
}

View File

@@ -1,15 +1,16 @@
// Types
import { TabContentItem as TabContentItemDefinition } from ".";
import { TabNavigationBase } from "../tab-navigation-base";
import { GridLayout } from "../../layouts/grid-layout";
// Requires
import { TabContentItemBase, traceCategory } from "./tab-content-item-common";
import { traceEnabled, traceWrite, traceMessageType } from "../../core/view";
import { View, traceWrite, traceMessageType } from "../../core/view";
export * from "./tab-content-item-common";
export class TabContentItem extends TabContentItemBase {
public nativeViewProtected: android.widget.TextView;
public nativeViewProtected: org.nativescript.widgets.GridLayout;
public tabItemSpec: org.nativescript.widgets.TabItemSpec;
public index: number;
@@ -17,6 +18,26 @@ export class TabContentItem extends TabContentItemBase {
return true;
}
public createNativeView() {
const layout = new org.nativescript.widgets.GridLayout(this._context);
layout.addRow(new org.nativescript.widgets.ItemSpec(1, org.nativescript.widgets.GridUnitType.star));
return layout;
}
public initNativeView(): void {
super.initNativeView();
}
public _addViewToNativeVisualTree(child: View, atIndex?: number): boolean {
// Set the row property for the child
if (this.nativeViewProtected && child.nativeViewProtected) {
GridLayout.setRow(child, 0);
}
return super._addViewToNativeVisualTree(child, atIndex);
}
public disposeNativeView(): void {
super.disposeNativeView();
(<TabContentItemDefinition>this).canBeLoaded = false;

View File

@@ -4,16 +4,12 @@
*/ /** */
import { View, ViewBase } from "../../core/view";
import { ContentView } from "../../content-view";
/**
* Represents a tab navigation content entry.
*/
export class TabContentItem extends ViewBase {
/**
* Gets or sets the view of the TabViewItem.
*/
public view: View;
export class TabContentItem extends ContentView {
/**
* @private
*/

View File

@@ -144,6 +144,12 @@ export class TabNavigationBase extends View {
*/
setTabBarHighlightColor(value: any)
/**
* @private
* Method is intended to be overridden by inheritors and used as "protected"
*/
setTabBarItemTitle(tabStripItem: TabStripItem, value: any): any
/**
* @private
* Method is intended to be overridden by inheritors and used as "protected"
@@ -168,6 +174,12 @@ export class TabNavigationBase extends View {
*/
setTabBarItemColor(tabStripItem: TabStripItem, value: any): void
/**
* @private
* Method is intended to be overridden by inheritors and used as "protected"
*/
setTabBarIconColor(tabStripItem: TabStripItem, value: any): void
/**
* @private
* Method is intended to be overridden by inheritors and used as "protected"

View File

@@ -45,7 +45,7 @@ export class TabNavigationBase extends View implements TabNavigationBaseDefiniti
get _selectedView(): View {
let selectedIndex = this.selectedIndex;
return selectedIndex > -1 ? this.items[selectedIndex].view : null;
return selectedIndex > -1 ? this.items[selectedIndex].content : null;
}
get _childrenCount(): number {
@@ -72,7 +72,7 @@ export class TabNavigationBase extends View implements TabNavigationBaseDefiniti
const items = this.items;
if (items) {
items.forEach((item, i) => {
callback(item.view);
callback(item.content);
});
}
}
@@ -84,8 +84,8 @@ export class TabNavigationBase extends View implements TabNavigationBaseDefiniti
if (newItems) {
newItems.forEach(item => {
if (!item.view) {
throw new Error(`TabContentItem must have a view.`);
if (!item.content) {
throw new Error(`TabContentItem must have a content (view).`);
}
this._addView(item);
@@ -152,6 +152,10 @@ export class TabNavigationBase extends View implements TabNavigationBaseDefiniti
// overridden by inheritors
}
public setTabBarItemTitle(tabStripItem: TabStripItem, value: any): void {
// overridden by inheritors
}
public getTabBarItemBackgroundColor(tabStripItem: TabStripItem): any {
// overridden by inheritors
return null;
@@ -170,6 +174,10 @@ export class TabNavigationBase extends View implements TabNavigationBaseDefiniti
// overridden by inheritors
}
public setTabBarIconColor(tabStripItem: TabStripItem, value: any): void {
// overridden by inheritors
}
public getTabBarItemFontSize(tabStripItem: TabStripItem): any {
// overridden by inheritors
return null;

View File

@@ -1,5 +1,6 @@
// Types
import { TabStripItem as TabStripItemDefinition } from ".";
import { PropertyChangeData } from "../../../data/observable";
import { TabNavigationBase } from "../tab-navigation-base";
import { TabStrip } from "../tab-strip";
import { Image } from "../../image/image";
@@ -9,10 +10,8 @@ import { AddChildFromBuilder } from "../../core/view";
// Requires
import {
View, CSSType, backgroundColorProperty, backgroundInternalProperty, colorProperty,
fontSizeProperty, fontInternalProperty, PseudoClassHandler
View, ViewBase, CSSType, backgroundColorProperty, backgroundInternalProperty, PseudoClassHandler
} from "../../core/view";
import { textTransformProperty, TextTransform } from "../../text-base";
export * from "../../core/view";
export const traceCategory = "TabView";
@@ -23,14 +22,153 @@ export class TabStripItem extends View implements TabStripItemDefinition, AddChi
public static selectEvent = "select";
public static unselectEvent = "unselect";
public title: string;
public iconSource: string;
public image: Image;
public label: Label;
private _title: string;
private _iconSource: string;
private _highlightedHandler: () => void;
private _normalHandler: () => void;
private _labelColorHandler: (args: PropertyChangeData) => void;
private _labelFontHandler: (args: PropertyChangeData) => void;
private _labelTextTransformHandler: (args: PropertyChangeData) => void;
private _labelTextHandler: (args: PropertyChangeData) => void;
private _imageColorHandler: (args: PropertyChangeData) => void;
private _imageFontHandler: (args: PropertyChangeData) => void;
private _imageSrcHandler: (args: PropertyChangeData) => void;
get title(): string {
if (this.isLoaded) {
return this.label.text;
}
return this._title;
}
set title(value: string) {
this._title = value;
if (this.isLoaded) {
this.label.text = value;
}
}
get iconSource(): string {
if (this.isLoaded) {
return this.image.src;
}
return this._iconSource;
}
set iconSource(value: string) {
this._iconSource = value;
if (this.isLoaded) {
this.image.src = value;
}
}
public onLoaded() {
if (!this.image) {
const image = new Image();
image.src = this.iconSource;
this.image = image;
this._addView(this.image);
}
if (!this.label) {
const label = new Label();
label.text = this.title;
this.label = label;
this._addView(this.label);
}
super.onLoaded();
this._labelColorHandler = this._labelColorHandler || ((args: PropertyChangeData) => {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.setTabBarItemColor(this, args.value);
});
this.label.style.on("colorChange", this._labelColorHandler);
this._labelFontHandler = this._labelFontHandler || ((args: PropertyChangeData) => {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.setTabBarItemFontInternal(this, args.value);
});
this.label.style.on("fontInternalChange", this._labelFontHandler);
this._labelTextTransformHandler = this._labelTextTransformHandler || ((args: PropertyChangeData) => {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.setTabBarItemTextTransform(this, args.value);
});
this.label.style.on("textTransformChange", this._labelTextTransformHandler);
this._labelTextHandler = this._labelTextHandler || ((args: PropertyChangeData) => {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.setTabBarItemTitle(this, args.value);
});
this.label.on("textChange", this._labelTextHandler);
this._imageColorHandler = this._imageColorHandler || ((args: PropertyChangeData) => {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && (<any>tabStripParent).setTabBarIconColor(this, args.value);
});
this.image.style.on("colorChange", this._imageColorHandler);
this._imageFontHandler = this._imageFontHandler || ((args: PropertyChangeData) => {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && (<any>tabStripParent).setTabBarIconColor(this, args.value);
});
this.image.style.on("fontInternalChange", this._imageFontHandler);
this._imageSrcHandler = this._imageSrcHandler || ((args: PropertyChangeData) => {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && (<any>tabStripParent).setTabBarIconColor(this, args.value);
});
this.image.on("srcChange", this._imageSrcHandler);
}
public onUnloaded() {
super.onUnloaded();
this.label.style.off("colorChange", this._labelColorHandler);
this.label.style.off("fontInternalChange", this._labelFontHandler);
this.label.style.off("textTransformChange", this._labelTextTransformHandler);
this.label.style.off("textChange", this._labelTextHandler);
this.image.style.off("colorChange", this._imageColorHandler);
this.image.style.off("fontInternalChange", this._imageFontHandler);
this.image.style.off("srcChange", this._imageSrcHandler);
}
public eachChild(callback: (child: ViewBase) => boolean) {
if (this.label) {
callback(this.label);
}
if (this.image) {
callback(this.image);
}
}
public _addChildFromBuilder(name: string, value: any): void {
if (name === "Image") {
this.image = <Image>value;
@@ -99,56 +237,4 @@ export class TabStripItem extends View implements TabStripItemDefinition, AddChi
[backgroundInternalProperty.setNative](value: any) {
// disable the background CSS properties
}
[colorProperty.getDefault](): Color {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.getTabBarItemColor(this);
}
[colorProperty.setNative](value: Color) {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.setTabBarItemColor(this, value);
}
[fontSizeProperty.getDefault](): { nativeSize: number } {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.getTabBarItemFontSize(this);
}
[fontSizeProperty.setNative](value: number | { nativeSize: number }) {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.setTabBarItemFontSize(this, value);
}
[fontInternalProperty.getDefault](): any {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.getTabBarItemFontInternal(this);
}
[fontInternalProperty.setNative](value: any) {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.setTabBarItemFontInternal(this, value);
}
[textTransformProperty.getDefault](): any {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.getTabBarItemTextTransform(this);
}
[textTransformProperty.setNative](value: any) {
const parent = <TabStrip>this.parent;
const tabStripParent = parent && <TabNavigationBase>parent.parent;
return tabStripParent && tabStripParent.setTabBarItemTextTransform(this, value);
}
}

View File

@@ -51,6 +51,18 @@ export class TabStrip extends View implements TabStripDefinition, AddChildFromBu
}
}
public onItemsChanged(oldItems: TabStripItem[], newItems: TabStripItem[]): void {
if (oldItems) {
oldItems.forEach(item => this._removeView(item));
}
if (newItems) {
newItems.forEach(item => {
this._addView(item);
});
}
}
[backgroundColorProperty.getDefault](): Color {
const parent = <TabNavigationBase>this.parent;
@@ -112,7 +124,14 @@ export class TabStrip extends View implements TabStripDefinition, AddChildFromBu
return parent && parent.setTabBarHighlightColor(value);
}
}
}
export const itemsProperty = new Property<TabStrip, TabStripItem[]>({
name: "items", valueChanged: (target, oldValue, newValue) => {
target.onItemsChanged(oldValue, newValue);
}
});
itemsProperty.register(TabStrip);
export const iosIconRenderingModeProperty = new Property<TabStrip, "automatic" | "alwaysOriginal" | "alwaysTemplate">({ name: "iosIconRenderingMode", defaultValue: "automatic" });
iosIconRenderingModeProperty.register(TabStrip);

View File

@@ -82,7 +82,7 @@ function initializeNativeClasses() {
public onCreateView(inflater: android.view.LayoutInflater, container: android.view.ViewGroup, savedInstanceState: android.os.Bundle): android.view.View {
const tabItem = this.tab.items[this.index];
return tabItem.view.nativeViewProtected;
return tabItem.nativeViewProtected;
}
}
@@ -284,42 +284,58 @@ function initializeNativeClasses() {
}
function createTabItemSpec(tabStripItem: TabStripItem): org.nativescript.widgets.TabItemSpec {
let iconSource;
const tabItemSpec = new org.nativescript.widgets.TabItemSpec();
if (tabStripItem.backgroundColor instanceof Color) {
tabItemSpec.backgroundColor = tabStripItem.backgroundColor.android;
}
if (tabStripItem.isLoaded) {
const nestedLabel = tabStripItem.label;
let title = nestedLabel.text;
// Image and Label children of TabStripItem
// take priority over its `iconSource` and `title` properties
iconSource = tabStripItem.image ? tabStripItem.image.src : tabStripItem.iconSource;
tabItemSpec.title = tabStripItem.label ? tabStripItem.label.text : tabStripItem.title;
// TEXT-TRANSFORM
const textTransform = nestedLabel.style.textTransform;
if (textTransform) {
title = getTransformedText(title, textTransform);
}
tabItemSpec.title = title;
if (iconSource) {
if (iconSource.indexOf(RESOURCE_PREFIX) === 0) {
tabItemSpec.iconId = ad.resources.getDrawableId(iconSource.substr(RESOURCE_PREFIX.length));
if (tabItemSpec.iconId === 0) {
// TODO
// traceMissingIcon(iconSource);
}
} else {
let is = new ImageSource();
if (isFontIconURI(tabStripItem.iconSource)) {
const fontIconCode = tabStripItem.iconSource.split("//")[1];
const font = tabStripItem.style.fontInternal;
const color = tabStripItem.style.color;
is = fromFontIconCode(fontIconCode, font, color);
// BACKGROUND-COLOR
const backgroundColor = tabStripItem.style.backgroundColor;
if (backgroundColor) {
tabItemSpec.backgroundColor = backgroundColor.android;
}
// COLOR
const color = nestedLabel.style.color;
if (color) {
tabItemSpec.color = color.android;
}
// FONT
const fontInternal = nestedLabel.style.fontInternal;
if (fontInternal) {
tabItemSpec.fontSize = fontInternal.fontSize;
tabItemSpec.typeFace = fontInternal.getAndroidTypeface();
}
// ICON
const iconSource = tabStripItem.image && tabStripItem.image.src;
if (iconSource) {
if (iconSource.indexOf(RESOURCE_PREFIX) === 0) {
tabItemSpec.iconId = ad.resources.getDrawableId(iconSource.substr(RESOURCE_PREFIX.length));
if (tabItemSpec.iconId === 0) {
// TODO:
// traceMissingIcon(iconSource);
}
} else {
is = fromFileOrResource(tabStripItem.iconSource);
}
const icon = _getIcon(tabStripItem);
if (is) {
// TODO: Make this native call that accepts string so that we don't load Bitmap in JS.
tabItemSpec.iconDrawable = new android.graphics.drawable.BitmapDrawable(application.android.context.getResources(), is.android);
} else {
// TODO
// traceMissingIcon(iconSource);
if (icon) {
// 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;
} else {
// TODO:
// traceMissingIcon(iconSource);
}
}
}
}
@@ -327,6 +343,25 @@ function createTabItemSpec(tabStripItem: TabStripItem): org.nativescript.widgets
return tabItemSpec;
}
function _getIcon(tabStripItem: TabStripItem): android.graphics.drawable.BitmapDrawable {
const iconSource = tabStripItem.image && tabStripItem.image.src;
let is = new ImageSource();
if (isFontIconURI(iconSource)) {
const fontIconCode = iconSource.split("//")[1];
const target = tabStripItem.image ? tabStripItem.image : tabStripItem;
const font = target.style.fontInternal;
const color = target.style.color;
is = fromFontIconCode(fontIconCode, font, color);
} else {
is = fromFileOrResource(iconSource);
}
const image = new android.graphics.drawable.BitmapDrawable(application.android.context.getResources(), is.android);
return image;
}
let defaultAccentColor: number = undefined;
function getDefaultAccentColor(context: android.content.Context): number {
if (defaultAccentColor === undefined) {
@@ -337,11 +372,15 @@ function getDefaultAccentColor(context: android.content.Context): number {
return defaultAccentColor;
}
function setElevation(grid: org.nativescript.widgets.GridLayout, tabsBar: org.nativescript.widgets.TabsBar) {
function setElevation(grid: org.nativescript.widgets.GridLayout, tabsBar: org.nativescript.widgets.TabsBar, tabsPosition: string) {
const compat = <any>androidx.core.view.ViewCompat;
if (compat.setElevation) {
const val = DEFAULT_ELEVATION * layout.getDisplayDensity();
compat.setElevation(grid, val);
if (tabsPosition === "top") {
compat.setElevation(grid, val);
}
compat.setElevation(tabsBar, val);
}
}
@@ -422,7 +461,7 @@ export class Tabs extends TabsBase {
nativeView.addView(tabsBar);
(<any>nativeView).tabsBar = tabsBar;
setElevation(nativeView, tabsBar);
setElevation(nativeView, tabsBar, this.tabsPosition);
if (accentColor) {
tabsBar.setSelectedIndicatorColors([accentColor]);
@@ -471,12 +510,12 @@ export class Tabs extends TabsBase {
toUnload.forEach(index => {
const item = items[index];
if (items[index]) {
item.unloadView(item.view);
item.unloadView(item.content);
}
});
const newItem = items[newIndex];
const selectedView = newItem && newItem.view;
const selectedView = newItem && newItem.content;
if (selectedView instanceof Frame) {
(<Frame>selectedView)._pushInFrameStackRecursive();
}
@@ -484,7 +523,7 @@ export class Tabs extends TabsBase {
toLoad.forEach(index => {
const item = items[index];
if (this.isLoaded && items[index]) {
item.loadView(item.view);
item.loadView(item.content);
}
});
}
@@ -661,20 +700,6 @@ export class Tabs extends TabsBase {
}
}
public getTabBarColor(): number {
return this._tabsBar.getTabTextColor();
}
public setTabBarColor(value: number | Color): void {
if (value instanceof Color) {
this._tabsBar.setTabTextColor(value.android);
this._tabsBar.setSelectedTabTextColor(value.android);
} else {
this._tabsBar.setTabTextColor(value);
this._tabsBar.setSelectedTabTextColor(value);
}
}
public getTabBarHighlightColor(): number {
return getDefaultAccentColor(this._context);
}
@@ -684,15 +709,18 @@ export class Tabs extends TabsBase {
this._tabsBar.setSelectedIndicatorColors([color]);
}
public setTabBarItemBackgroundColor(tabStripItem: TabStripItem, value: android.graphics.drawable.Drawable | Color): void {
public setTabBarItemTitle(tabStripItem: TabStripItem, value: string): void {
// TODO: Should figure out a way to do it directly with the the nativeView
const tabStripItemIndex = this.tabStrip.items.indexOf(tabStripItem);
const tabItemSpec = createTabItemSpec(tabStripItem);
this.updateAndroidItemAt(tabStripItemIndex, tabItemSpec);
}
public getTabBarItemColor(tabStripItem: TabStripItem): number {
return tabStripItem.nativeViewProtected.getCurrentTextColor();
public setTabBarItemBackgroundColor(tabStripItem: TabStripItem, value: android.graphics.drawable.Drawable | Color): void {
// TODO: Should figure out a way to do it directly with the the nativeView
const tabStripItemIndex = this.tabStrip.items.indexOf(tabStripItem);
const tabItemSpec = createTabItemSpec(tabStripItem);
this.updateAndroidItemAt(tabStripItemIndex, tabItemSpec);
}
public setTabBarItemColor(tabStripItem: TabStripItem, value: number | Color): void {
@@ -703,45 +731,24 @@ export class Tabs extends TabsBase {
}
}
public getTabBarItemFontSize(tabStripItem: TabStripItem): { nativeSize: number } {
return { nativeSize: tabStripItem.nativeViewProtected.getTextSize() };
public setTabBarIconColor(tabStripItem: TabStripItem, value: number | Color): void {
const index = (<any>tabStripItem).index;
const tabBarItem = this._tabsBar.getViewForItemAt(index);
const imgView = <android.widget.ImageView>tabBarItem.getChildAt(0);
const drawable = _getIcon(tabStripItem);
imgView.setImageDrawable(drawable);
}
public setTabBarItemFontSize(tabStripItem: TabStripItem, value: number | { nativeSize: number }): void {
if (typeof value === "number") {
tabStripItem.nativeViewProtected.setTextSize(value);
} else {
tabStripItem.nativeViewProtected.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, value.nativeSize);
}
public setTabBarItemFontInternal(tabStripItem: TabStripItem, value: Font): void {
tabStripItem.nativeViewProtected.setTextSize(value.fontSize);
tabStripItem.nativeViewProtected.setTypeface(value.getAndroidTypeface());
}
public getTabBarItemFontInternal(tabStripItem: TabStripItem): android.graphics.Typeface {
return tabStripItem.nativeViewProtected.getTypeface();
}
public setTabBarItemFontInternal(tabStripItem: TabStripItem, value: Font | android.graphics.Typeface): void {
tabStripItem.nativeViewProtected.setTypeface(value instanceof Font ? value.getAndroidTypeface() : value);
}
private _defaultTransformationMethod: android.text.method.TransformationMethod;
public getTabBarItemTextTransform(tabStripItem: TabStripItem): "default" {
return "default";
}
public setTabBarItemTextTransform(tabStripItem: TabStripItem, value: TextTransform | "default"): void {
const tv = tabStripItem.nativeViewProtected;
this._defaultTransformationMethod = this._defaultTransformationMethod || tv.getTransformationMethod();
if (value === "default") {
tv.setTransformationMethod(this._defaultTransformationMethod);
tv.setText(tabStripItem.title);
} else {
const result = getTransformedText(tabStripItem.title, value);
tv.setText(result);
tv.setTransformationMethod(null);
}
public setTabBarItemTextTransform(tabStripItem: TabStripItem, value: TextTransform): void {
const nestedLabel = tabStripItem.label;
const title = getTransformedText(nestedLabel.text, value);
tabStripItem.nativeViewProtected.setText(title);
}
[selectedIndexProperty.setNative](value: number) {

View File

@@ -532,7 +532,7 @@ export class Tabs extends TabsBase {
super.onLoaded();
const selectedIndex = this.selectedIndex;
const selectedView = this.items && this.items[selectedIndex] && this.items[selectedIndex].view;
const selectedView = this.items && this.items[selectedIndex] && this.items[selectedIndex].content;
if (selectedView instanceof Frame) {
(<Frame>selectedView)._pushInFrameStackRecursive();
}
@@ -540,10 +540,8 @@ export class Tabs extends TabsBase {
this._ios.dataSource = this._dataSource;
this._ios.delegate = this._delegate;
if (!this.tabBarItems) {
const tabStripItems = this.tabStrip ? this.tabStrip.items : null;
this.setTabStripItems(tabStripItems);
}
const tabStripItems = this.tabStrip ? this.tabStrip.items : null;
this.setTabStripItems(tabStripItems);
}
public onUnloaded() {
@@ -611,12 +609,12 @@ export class Tabs extends TabsBase {
toUnload.forEach(index => {
const item = items[index];
if (items[index]) {
item.unloadView(item.view);
item.unloadView(item.content);
}
});
const newItem = items[newIndex];
const selectedView = newItem && newItem.view;
const selectedView = newItem && newItem.content;
if (selectedView instanceof Frame) {
selectedView._pushInFrameStackRecursive();
}
@@ -624,7 +622,7 @@ export class Tabs extends TabsBase {
toLoad.forEach(index => {
const item = items[index];
if (this.isLoaded && items[index]) {
item.loadView(item.view);
item.loadView(item.content);
}
});
}
@@ -699,7 +697,7 @@ export class Tabs extends TabsBase {
// }
public getViewController(item: TabContentItem): UIViewController {
let newController: UIViewController = item.view ? item.view.viewController : null;
let newController: UIViewController = item.content ? item.content.viewController : null;
if (newController) {
(<any>item).setViewController(newController, newController.view);
@@ -707,17 +705,17 @@ export class Tabs extends TabsBase {
return newController;
}
if (item.view.ios instanceof UIViewController) {
newController = item.view.ios;
if (item.content.ios instanceof UIViewController) {
newController = item.content.ios;
(<any>item).setViewController(newController, newController.view);
} else if (item.view.ios && item.view.ios.controller instanceof UIViewController) {
newController = item.view.ios.controller;
} else if (item.content.ios && item.content.ios.controller instanceof UIViewController) {
newController = item.content.ios.controller;
(<any>item).setViewController(newController, newController.view);
} else {
newController = iosView.UILayoutViewController.initWithOwner(new WeakRef(item.view)) as UIViewController;
newController.view.addSubview(item.view.nativeViewProtected);
item.view.viewController = newController;
(<any>item).setViewController(newController, item.view.nativeViewProtected);
newController = iosView.UILayoutViewController.initWithOwner(new WeakRef(item.content)) as UIViewController;
newController.view.addSubview(item.content.nativeViewProtected);
item.content.viewController = newController;
(<any>item).setViewController(newController, item.content.nativeViewProtected);
}
return newController;
@@ -850,8 +848,8 @@ export class Tabs extends TabsBase {
let image: UIImage;
let title: string;
image = this._getIcon(item);
title = item.label ? item.label.text : item.title;
image = item.isLoaded && this._getIcon(item);
title = item.label && item.label.text;
if (!this.tabStrip._hasImage) {
this.tabStrip._hasImage = !!image;
@@ -884,20 +882,21 @@ export class Tabs extends TabsBase {
}
public _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 : tabStripItem.iconSource;
const iconSource = tabStripItem.image && tabStripItem.image.src;
if (!iconSource) {
return null;
}
let image: UIImage = this._iconsCache[iconSource];
const target = tabStripItem.image;
const font = target.style.fontInternal;
const color = target.style.color;
const iconTag = [iconSource, font.fontStyle, font.fontWeight, font.fontSize, font.fontFamily, color].join(";");
let image: UIImage = this._iconsCache[iconTag];
if (!image) {
let is = new ImageSource;
if (isFontIconURI(iconSource)) {
const fontIconCode = iconSource.split("//")[1];
const font = tabStripItem.style.fontInternal;
const color = tabStripItem.style.color;
is = fromFontIconCode(fontIconCode, font, color);
} else {
is = fromFileOrResource(iconSource);
@@ -905,7 +904,7 @@ export class Tabs extends TabsBase {
if (is && is.ios) {
const originalRenderedImage = is.ios.imageWithRenderingMode(this._getIconRenderingMode());
this._iconsCache[iconSource] = originalRenderedImage;
this._iconsCache[iconTag] = originalRenderedImage;
image = originalRenderedImage;
} else {
// TODO