tabview-ios

This commit is contained in:
Hristo Hristov
2016-12-05 18:12:25 +02:00
parent 079830e9b5
commit 943d2dcd6b
6 changed files with 365 additions and 236 deletions

View File

@ -26,6 +26,10 @@ export interface PropertyOptions<T, U> {
valueConverter?: (value: any) => U
}
export interface CoerciblePropertyOptions<T, U> extends PropertyOptions<T, U> {
coerceValue(T, U): U
}
export interface ShorthandPropertyOptions {
name: string,
cssName: string;
@ -40,9 +44,9 @@ export interface CssPropertyOptions<T extends Style, U> extends PropertyOptions<
export class Property<T extends ViewBase, U> implements PropertyDescriptor {
private registered: boolean;
private name: string;
public key: symbol;
public native: symbol;
private readonly name: string;
public readonly key: symbol;
public readonly native: symbol;
public get: () => U;
public set: (value: U) => void;
@ -67,22 +71,137 @@ export class Property<T extends ViewBase, U> implements PropertyDescriptor {
let valueConverter = options.valueConverter;
this.set = function (this: T, value: any): void {
if (value === unsetValue) {
value = defaultValue;
}
let reset = value === unsetValue;
let unboxedValue: U;
let wrapped: boolean;
if (reset) {
unboxedValue = defaultValue;
} else {
wrapped = value && (<any>value).wrapped;
unboxedValue = wrapped ? WrappedValue.unwrap(value) : value;
let wrapped = value && value.wrapped;
let unboxedValue: U = wrapped ? WrappedValue.unwrap(value) : value;
if (valueConverter) {
unboxedValue = valueConverter(unboxedValue);
if (valueConverter && typeof unboxedValue === "string") {
unboxedValue = valueConverter(unboxedValue);
}
}
let currentValue = key in this ? this[key] : defaultValue;
let changed: boolean = equalityComparer ? !equalityComparer(currentValue, unboxedValue) : currentValue !== unboxedValue;
if (wrapped || changed) {
this[key] = unboxedValue;
if (reset) {
delete this[key];
} else {
this[key] = unboxedValue;
}
if (valueChanged) {
valueChanged(this, currentValue, unboxedValue);
}
if (this.hasListeners(eventName)) {
this.notify({
eventName: eventName,
propertyName: name,
object: this,
value: unboxedValue
});
}
let nativeObject = this.nativeView;
if (nativeObject) {
this[native] = unboxedValue;
}
if (affectsLayout) {
this.requestLayout();
}
}
}
this.get = function (): U {
return key in this ? this[key] : defaultValue;
}
symbolPropertyMap[key] = this;
}
public register(cls: { prototype: T }): void {
if (this.registered) {
throw new Error(`Property ${this.name} already registered.`);
}
this.registered = true;
Object.defineProperty(cls.prototype, this.name, this);
}
}
export class CoercibleProperty<T extends ViewBase, U> implements PropertyDescriptor {
private registered: boolean;
private readonly name: string;
public readonly key: symbol;
public readonly native: symbol;
public get: () => U;
public set: (value: U) => void;
public enumerable: boolean = true;
public configurable: boolean = true;
public readonly coerce: (target: T) => void;
constructor(options: CoerciblePropertyOptions<T, U>) {
let name = options.name;
this.name = name;
let key = Symbol(name + ":propertyKey");
this.key = key;
let native: symbol = Symbol(name + ":nativeKey");
this.native = native;
let coerceKey = Symbol(name + ":coerceKey");
let eventName = name + "Change";
let defaultValue: U = options.defaultValue;
let affectsLayout: boolean = options.affectsLayout;
let equalityComparer = options.equalityComparer;
let valueChanged = options.valueChanged;
let valueConverter = options.valueConverter;
let coerceCallback = options.coerceValue;
this.coerce = function (target: T): void {
let originalValue: U = coerceKey in target ? target[coerceKey] : defaultValue;
target[key] = originalValue;
}
this.set = function (this: T, value: U): void {
let reset = value === unsetValue;
let unboxedValue: U;
let wrapped: boolean;
if (reset) {
unboxedValue = defaultValue;
delete this[coerceKey];
} else {
wrapped = value && (<any>value).wrapped;
unboxedValue = wrapped ? WrappedValue.unwrap(value) : value;
if (valueConverter && typeof unboxedValue === "string") {
unboxedValue = valueConverter(unboxedValue);
}
this[coerceKey] = unboxedValue;
unboxedValue = coerceCallback(this, unboxedValue);
}
let currentValue = key in this ? this[key] : defaultValue;
let changed: boolean = equalityComparer ? !equalityComparer(currentValue, unboxedValue) : currentValue !== unboxedValue;
if (wrapped || changed) {
if (reset) {
delete this[key];
} else {
this[key] = unboxedValue;
}
if (valueChanged) {
valueChanged(this, currentValue, unboxedValue);
}
@ -170,16 +289,16 @@ export class InheritedProperty<T extends ViewBase, U> extends Property<T, U> {
that[sourceKey] = newValueSource;
if (currentValue !== newValue) {
let resetValue = newValueSource === ValueSource.Default;
let reset = newValueSource === ValueSource.Default;
that.eachChild((child) => {
let childValueSource = child[sourceKey];
if (resetValue) {
if (reset) {
if (childValueSource === ValueSource.Inherited) {
setFunc.call(child, unsetValue);
}
} else {
if (childValueSource <= ValueSource.Inherited) {
setInheritedValue.call(child, unboxedValue);
setInheritedValue.call(child, child.parent[key]);
}
}
return true;
@ -239,13 +358,14 @@ export class CssProperty<T extends Style, U> {
let dependentPropertyNativeKey = dependentProperty ? dependentProperty.native : undefined;
function setLocalValue(this: T, value: U): void {
if (value === unsetValue) {
let reset = value === unsetValue;
if (reset) {
value = defaultValue;
this[sourceKey] = ValueSource.Default;
delete this[sourceKey];
}
else {
this[sourceKey] = ValueSource.Local;
if (valueConverter) {
if (valueConverter && typeof value === "string") {
value = valueConverter(value);
}
}
@ -254,7 +374,12 @@ export class CssProperty<T extends Style, U> {
let changed: boolean = equalityComparer ? !equalityComparer(currentValue, value) : currentValue !== value;
if (changed) {
this[key] = value;
if (reset) {
delete this[key];
} else {
this[key] = value;
}
if (valueChanged) {
valueChanged(this, currentValue, value);
}
@ -284,8 +409,7 @@ export class CssProperty<T extends Style, U> {
}
function setCssValue(this: T, value: U): void {
let resetValue = value === unsetValue;
let newValueSource: ValueSource;
let reset = value === unsetValue;
let currentValueSource: number = this[sourceKey] || ValueSource.Default;
// We have localValueSource - NOOP.
@ -293,22 +417,26 @@ export class CssProperty<T extends Style, U> {
return;
}
if (resetValue) {
if (reset) {
value = defaultValue;
newValueSource = ValueSource.Default;
delete this[sourceKey];
} else {
newValueSource = ValueSource.Css;
if (valueConverter) {
this[sourceKey] = ValueSource.Css;
if (valueConverter && typeof value === "string") {
value = valueConverter(value);
}
}
let currentValue: U = key in this ? this[key] : defaultValue;
let changed: boolean = equalityComparer ? !equalityComparer(currentValue, value) : currentValue !== value;
this[sourceKey] = newValueSource;
if (changed) {
this[key] = value;
if (reset) {
delete this[key];
} else {
this[key] = value;
}
if (valueChanged) {
valueChanged(this, currentValue, value);
}
@ -395,9 +523,9 @@ export class InheritedCssProperty<T extends Style, U> extends CssProperty<T, U>
let dependentPropertyNativeKey = dependentProperty ? dependentProperty.native : undefined;
let setFunc = (valueSource: ValueSource) => function (this: T, value: any): void {
let resetValue = value === unsetValue;
let reset = value === unsetValue;
let currentValueSource: number = this[sourceKey] || ValueSource.Default;
if (resetValue) {
if (reset) {
// If we want to reset cssValue and we have localValue - return;
if (valueSource === ValueSource.Css && currentValueSource === ValueSource.Local) {
return;
@ -410,7 +538,7 @@ export class InheritedCssProperty<T extends Style, U> extends CssProperty<T, U>
let view = this.view;
let newValue: U;
if (resetValue) {
if (reset) {
// If unsetValue - we want to reset this property.
let parent = view.parent;
let style = parent ? parent.style : null
@ -421,11 +549,11 @@ export class InheritedCssProperty<T extends Style, U> extends CssProperty<T, U>
}
else {
newValue = defaultValue;
this[sourceKey] = ValueSource.Default;
delete this[sourceKey];
}
} else {
this[sourceKey] = valueSource;
if (valueConverter) {
if (valueConverter && typeof value === "string") {
newValue = valueConverter(value);
} else {
newValue = value;
@ -436,7 +564,12 @@ export class InheritedCssProperty<T extends Style, U> extends CssProperty<T, U>
let changed: boolean = equalityComparer ? !equalityComparer(currentValue, newValue) : currentValue !== newValue;
if (changed) {
this[key] = newValue;
if (reset) {
delete this[key];
} else {
this[key] = newValue;
}
if (valueChanged) {
valueChanged(this, currentValue, newValue);
}
@ -466,7 +599,7 @@ export class InheritedCssProperty<T extends Style, U> extends CssProperty<T, U>
view.eachChild((child) => {
let childStyle = child.style;
let childValueSource = childStyle[sourceKey] || ValueSource.Default;
if (resetValue) {
if (reset) {
if (childValueSource === ValueSource.Inherited) {
setDefaultFunc.call(childStyle, unsetValue);
}

View File

@ -62,6 +62,10 @@ declare module "ui/core/properties" {
readonly valueConverter?: (value: any) => U
}
export interface CoerciblePropertyOptions<T, U> extends PropertyOptions<T, U> {
coerceValue(T, U): U
}
interface CssPropertyOptions<T extends Style, U> extends PropertyOptions<T, U> {
readonly cssName: string;
}
@ -73,6 +77,14 @@ declare module "ui/core/properties" {
public register(cls: { prototype: T }): void;
}
class CoercibleProperty<T extends ViewBase, U> implements TypedPropertyDescriptor<U> {
constructor(options: CoerciblePropertyOptions<T, U>);
public readonly native: symbol;
public readonly coerce: (target: T) => void;
public register(cls: { prototype: T }): void;
}
class InheritedProperty<T extends ViewBase, U> extends Property<T, U> {
constructor(options: PropertyOptions<T, U>);
}

View File

@ -1,5 +1,5 @@
import { TabView as TabViewDefinition, TabViewItem as TabViewItemDefinition } from "ui/tab-view";
import { Property } from "ui/core/properties";
import { Property, CoercibleProperty } from "ui/core/properties";
import { View, AddArrayFromBuilder } from "ui/core/view";
import { Bindable } from "ui/core/bindable";
import { isIOS } from "platform";
@ -122,20 +122,6 @@ export class TabViewBase extends View implements TabViewDefinition, AddArrayFrom
}
}
public _onSelectedIndexPropertyChangedSetNativeValue() {
let index = this.selectedIndex;
if (index < 0) {
return;
}
if (this.items) {
if (index >= this.items.length) {
this.selectedIndex = unsetValue;
throw new Error("SelectedIndex should be between [0, items.length)");
}
}
}
get _selectedView(): View {
let items = this.items;
let selectedIndex = this.selectedIndex;
@ -175,7 +161,7 @@ export class TabViewBase extends View implements TabViewDefinition, AddArrayFrom
public _onBindingContextChanged(oldValue: any, newValue: any) {
super._onBindingContextChanged(oldValue, newValue);
if (this.items && this.items.length > 0) {
for (let i = 0, length = this.items.length; i < length; i++) {
this.items[i].bindingContext = newValue;
}
@ -191,13 +177,6 @@ export class TabViewBase extends View implements TabViewDefinition, AddArrayFrom
// iOS sepcific
}
get [selectedIndexProperty.native](): number {
return -1;
}
set [selectedIndexProperty.native](value: number) {
this._onSelectedIndexPropertyChangedSetNativeValue();
}
public onItemsPropertyChanged(oldValue: TabViewItemDefinition[], newValue: TabViewItemDefinition[]) {
this.previousItems = oldValue;
}
@ -206,11 +185,29 @@ export class TabViewBase extends View implements TabViewDefinition, AddArrayFrom
export const itemsProperty = new Property<TabViewBase, TabViewItemBase[]>({
name: "items", valueChanged: (target, oldValue, newValue) => {
target.onItemsPropertyChanged(oldValue, newValue);
selectedIndexProperty.coerce(target);
}
});
itemsProperty.register(TabViewBase);
export const selectedIndexProperty = new Property<TabViewBase, number>({ name: "selectedIndex", defaultValue: -1, affectsLayout: isIOS });
export const selectedIndexProperty = new CoercibleProperty<TabViewBase, number>({
name: "selectedIndex", defaultValue: -1, affectsLayout: isIOS, valueChanged: (target, oldValue, newValue) => {
let args = { eventName: TabViewBase.selectedIndexChangedEvent, object: this, oldIndex: oldValue, newIndex: newValue };
target.notify(args);
}, coerceValue: (target, value) => {
let items = target.items;
if (items) {
let max = items.length - 1;
if (value > max) {
value = max;
}
} else {
value = -1;
}
return value;
}
});
selectedIndexProperty.register(TabViewBase);
export const selectedColorProperty = new Property<TabViewBase, Color>({ name: "selectedColor" });

View File

@ -1,17 +1,16 @@
import { TabViewBase, TabViewItemBase, itemsProperty, selectedIndexProperty, selectedColorProperty, tabsBackgroundColorProperty, traceCategory } from "./tab-view-common"
import { View, colorProperty, fontInternalProperty } from "ui/core/view";
import { View, colorProperty, fontInternalProperty, layout } from "ui/core/view";
import { Property } from "ui/core/properties";
import { Bindable } from "ui/core/bindable";
import { isIOS } from "platform";
import { Color } from "color";
import { Font } from "ui/styling/font";
import { fromFileOrResource } from "image-source";
import trace = require("trace");
import { enabled as traceEnabled, write as traceWrite } from "trace";
import { RESOURCE_PREFIX, ad } from "utils/utils";
export * from "./tab-view-common";
const VIEWS_STATES = "_viewStates";
const ACCENT_COLOR = "colorAccent";
const PRIMARY_COLOR = "colorPrimary";
@ -59,8 +58,8 @@ function ensurePagerAdapterClass() {
}
instantiateItem(container: android.view.ViewGroup, index: number) {
if (trace.enabled) {
trace.write("TabView.PagerAdapter.instantiateItem; container: " + container + "; index: " + index, traceCategory);
if (traceEnabled) {
traceWrite("TabView.PagerAdapter.instantiateItem; container: " + container + "; index: " + index, traceCategory);
}
let item = this.items[index];
@ -69,8 +68,8 @@ function ensurePagerAdapterClass() {
}
if (this[VIEWS_STATES]) {
if (trace.enabled) {
trace.write("TabView.PagerAdapter.instantiateItem; restoreHierarchyState: " + item.view, traceCategory);
if (traceEnabled) {
traceWrite("TabView.PagerAdapter.instantiateItem; restoreHierarchyState: " + item.view, traceCategory);
}
item.view._nativeView.restoreHierarchyState(this[VIEWS_STATES]);
}
@ -80,8 +79,8 @@ function ensurePagerAdapterClass() {
}
destroyItem(container: android.view.ViewGroup, index: number, _object: any) {
if (trace.enabled) {
trace.write("TabView.PagerAdapter.destroyItem; container: " + container + "; index: " + index + "; _object: " + _object, traceCategory);
if (traceEnabled) {
traceWrite("TabView.PagerAdapter.destroyItem; container: " + container + "; index: " + index + "; _object: " + _object, traceCategory);
}
let item = this.items[index];
let nativeView = item.view._nativeView;
@ -104,8 +103,8 @@ function ensurePagerAdapterClass() {
}
saveState(): android.os.Parcelable {
if (trace.enabled) {
trace.write("TabView.PagerAdapter.saveState", traceCategory);
if (traceEnabled) {
traceWrite("TabView.PagerAdapter.saveState", traceCategory);
}
let owner: TabView = this.owner;
@ -132,8 +131,8 @@ function ensurePagerAdapterClass() {
}
restoreState(state: android.os.Parcelable, loader: java.lang.ClassLoader) {
if (trace.enabled) {
trace.write("TabView.PagerAdapter.restoreState", traceCategory);
if (traceEnabled) {
traceWrite("TabView.PagerAdapter.restoreState", traceCategory);
}
let bundle: android.os.Bundle = <android.os.Bundle>state;
bundle.setClassLoader(loader);
@ -180,8 +179,8 @@ export class TabView extends TabViewBase {
}
public _createUI() {
if (trace.enabled) {
trace.write("TabView._createUI(" + this + ");", traceCategory);
if (traceEnabled) {
traceWrite("TabView._createUI(" + this + ");", traceCategory);
}
this._grid = new org.nativescript.widgets.GridLayout(this._context);
@ -193,12 +192,12 @@ export class TabView extends TabViewBase {
this.setElevation();
let accentColor = utils.ad.resources.getPalleteColor(ACCENT_COLOR, this._context);
let accentColor = ad.resources.getPalleteColor(ACCENT_COLOR, this._context);
if (accentColor) {
this._tabLayout.setSelectedIndicatorColors([accentColor]);
}
let primaryColor = utils.ad.resources.getPalleteColor(PRIMARY_COLOR, this._context);
let primaryColor = ad.resources.getPalleteColor(PRIMARY_COLOR, this._context);
if (primaryColor) {
this._tabLayout.setBackgroundColor(primaryColor);
}
@ -225,7 +224,7 @@ export class TabView extends TabViewBase {
private setElevation() {
let compat = <any>android.support.v4.view.ViewCompat;
if (compat.setElevation) {
let val = DEFAULT_ELEVATION * utils.layout.getDisplayDensity();
let val = DEFAULT_ELEVATION * layout.getDisplayDensity();
compat.setElevation(this._grid, val);
compat.setElevation(this._tabLayout, val);
}
@ -271,7 +270,8 @@ export class TabView extends TabViewBase {
}
public _updateTabForItem(item: TabViewItem) {
if (this.items && this.items.length > 0) {
let items = this.items;
if (items && items.length > 0) {
let index = this.items.indexOf(item);
if (index >= 0) {
this._tabLayout.updateItemAt(index, this.createTabItem(item));
@ -279,39 +279,17 @@ export class TabView extends TabViewBase {
}
}
public _onSelectedIndexPropertyChangedSetNativeValue() {
if (trace.enabled) {
trace.write("TabView._onSelectedIndexPropertyChangedSetNativeValue(" + data.oldValue + " ---> " + data.newValue + ");", traceCategory);
}
super._onSelectedIndexPropertyChangedSetNativeValue(data);
let index = data.newValue;
if (!types.isNullOrUndefined(index)) {
// Select the respective page in the ViewPager
let viewPagerSelectedIndex = this._viewPager.getCurrentItem();
if (viewPagerSelectedIndex !== index) {
if (trace.enabled) {
trace.write("TabView this._viewPager.setCurrentItem(" + index + ", true);", traceCategory);
}
this._viewPager.setCurrentItem(index, true);
}
}
let args = { eventName: TabView.selectedIndexChangedEvent, object: this, oldIndex: data.oldValue, newIndex: data.newValue };
this.notify(args);
}
private createTabItem(item: TabViewItem): org.nativescript.widgets.TabItemSpec {
let result = new org.nativescript.widgets.TabItemSpec();
result.title = item.title;
if (item.iconSource) {
if (item.iconSource.indexOf(utils.RESOURCE_PREFIX) === 0) {
result.iconId = utils.ad.resources.getDrawableId(item.iconSource.substr(utils.RESOURCE_PREFIX.length));
if (item.iconSource.indexOf(RESOURCE_PREFIX) === 0) {
result.iconId = ad.resources.getDrawableId(item.iconSource.substr(RESOURCE_PREFIX.length));
}
else {
let is = imageSource.fromFileOrResource(item.iconSource);
let is = fromFileOrResource(item.iconSource);
if (is) {
result.iconDrawable = new android.graphics.drawable.BitmapDrawable(is.android);
}
@ -321,6 +299,16 @@ export class TabView extends TabViewBase {
return result;
}
get [selectedIndexProperty.native](): number {
return -1;
}
set [selectedIndexProperty.native](value: number) {
if (traceEnabled) {
traceWrite("TabView this._viewPager.setCurrentItem(" + value + ", true);", traceCategory);
}
this._viewPager.setCurrentItem(value, true);
}
get [itemsProperty.native](): TabViewItemBase[] {
return null;
}

View File

@ -1,24 +1,15 @@
import common = require("./tab-view-common");
import definition = require("ui/tab-view");
import dependencyObservable = require("ui/core/dependency-observable");
import trace = require("trace");
import view = require("ui/core/view");
import types = require("utils/types");
import color = require("color");
import * as imageSourceModule from "image-source";
import style = require("ui/styling/style");
import { TabViewBase, TabViewItemBase, itemsProperty, selectedIndexProperty, selectedColorProperty, tabsBackgroundColorProperty, traceCategory } from "./tab-view-common"
import { View, colorProperty, fontInternalProperty, layout } from "ui/core/view";
import { Color } from "color";
import { Font } from "ui/styling/font";
import { fromFileOrResource } from "image-source";
import { Page } from "ui/page";
import * as utils from "utils/utils";
import getter = utils.ios.getter;
import { ios } from "utils/utils";
import { enabled as traceEnabled, write as traceWrite, categories as traceCategories } from "trace";
global.moduleMerge(common, exports);
import getter = ios.getter;
var imageSource: typeof imageSourceModule;
function ensureImageSource() {
if (!imageSource) {
imageSource = require("image-source");
}
}
export * from "./tab-view-common";
class UITabBarControllerImpl extends UITabBarController {
@ -31,8 +22,8 @@ class UITabBarControllerImpl extends UITabBarController {
}
public viewDidLayoutSubviews(): void {
if (trace.enabled) {
trace.write("TabView.UITabBarControllerClass.viewDidLayoutSubviews();", trace.categories.Debug);
if (traceEnabled) {
traceWrite("TabView.UITabBarControllerClass.viewDidLayoutSubviews();", traceCategories.Debug);
}
super.viewDidLayoutSubviews();
let owner = this._owner.get();
@ -54,25 +45,25 @@ class UITabBarControllerDelegateImpl extends NSObject implements UITabBarControl
}
public tabBarControllerShouldSelectViewController(tabBarController: UITabBarController, viewController: UIViewController): boolean {
if (trace.enabled) {
trace.write("TabView.delegate.SHOULD_select(" + tabBarController + ", " + viewController + ");", trace.categories.Debug);
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);
}
return true;
return true;
}
public tabBarControllerDidSelectViewController(tabBarController: UITabBarController, viewController: UIViewController): void {
if (trace.enabled) {
trace.write("TabView.delegate.DID_select(" + tabBarController + ", " + viewController + ");", trace.categories.Debug);
if (traceEnabled) {
traceWrite("TabView.delegate.DID_select(" + tabBarController + ", " + viewController + ");", traceCategories.Debug);
}
let owner = this._owner.get();
if (owner) {
owner._onViewControllerShown(viewController);
@ -92,10 +83,10 @@ class UINavigationControllerDelegateImpl extends NSObject implements UINavigatio
}
navigationControllerWillShowViewControllerAnimated(navigationController: UINavigationController, viewController: UIViewController, animated: boolean): void {
if (trace.enabled) {
trace.write("TabView.moreNavigationController.WILL_show(" + navigationController + ", " + viewController + ", " + animated + ");", trace.categories.Debug);
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.
@ -106,8 +97,8 @@ class UINavigationControllerDelegateImpl extends NSObject implements UINavigatio
}
navigationControllerDidShowViewControllerAnimated(navigationController: UINavigationController, viewController: UIViewController, animated: boolean): void {
if (trace.enabled) {
trace.write("TabView.moreNavigationController.DID_show(" + navigationController + ", " + viewController + ", " + animated + ");", trace.categories.Debug);
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;
@ -118,25 +109,29 @@ class UINavigationControllerDelegateImpl extends NSObject implements UINavigatio
}
}
export class TabViewItem extends common.TabViewItem {
function updateItemTitlePosition(tabBarItem: UITabBarItem): void {
if (typeof (<any>tabBarItem).setTitlePositionAdjustment === "function") {
(<any>tabBarItem).setTitlePositionAdjustment({ horizontal: 0, vertical: -20 });
}
else {
tabBarItem.titlePositionAdjustment = { horizontal: 0, vertical: -20 };
}
}
export class TabViewItem extends TabViewItemBase {
public _controller: UIViewController;
public _parent: TabView;
public _update() {
if (this._parent && this._controller) {
var icon = this._parent._getIcon(this.iconSource);
//TODO: Implement initWithSystemItem to support standard system icons
var tabBarItem = UITabBarItem.alloc().initWithTitleImageTag((this.title || ""), icon, this._parent.items.indexOf(this));
const icon = this._parent._getIcon(this.iconSource);
//TODO: Implement initWithSystemItem to support standard system icons
const tabBarItem = UITabBarItem.alloc().initWithTitleImageTag((this.title || ""), icon, this._parent.items.indexOf(this));
if (!icon) {
if (types.isFunction((<any>tabBarItem).setTitlePositionAdjustment)) {
(<any>tabBarItem).setTitlePositionAdjustment({ horizontal: 0, vertical: -20 });
}
else {
tabBarItem.titlePositionAdjustment = { horizontal: 0, vertical: -20 };
}
updateItemTitlePosition(tabBarItem);
}
var states = getTitleAttributesForStates(this._parent);
const states = getTitleAttributesForStates(this._parent);
tabBarItem.setTitleTextAttributesForState(states.normalState, UIControlState.Normal);
tabBarItem.setTitleTextAttributesForState(states.selectedState, UIControlState.Selected);
this._controller.tabBarItem = tabBarItem;
@ -144,7 +139,21 @@ export class TabViewItem extends common.TabViewItem {
}
}
export class TabView extends common.TabView {
function selectedColorPropertyChanged(data: dependencyObservable.PropertyChangeData) {
const tabView = <TabView>data.object;
tabView._updateIOSTabBarColorsAndFonts();
}
(<proxy.PropertyMetadata>common.TabView.selectedColorProperty.metadata).onSetNativeValue = selectedColorPropertyChanged;
function tabsBackgroundColorPropertyChanged(data: dependencyObservable.PropertyChangeData) {
const tabView = <TabView>data.object;
if (data.newValue instanceof color.Color) {
tabView.ios.tabBar.barTintColor = data.newValue.ios;
}
}
(<proxy.PropertyMetadata>common.TabView.tabsBackgroundColorProperty.metadata).onSetNativeValue = tabsBackgroundColorPropertyChanged;
export class TabView extends TabViewBase {
public _ios: UITabBarControllerImpl;
private _delegate: UITabBarControllerDelegateImpl;
private _moreNavigationControllerDelegate: UINavigationControllerDelegateImpl;
@ -182,63 +191,60 @@ export class TabView extends common.TabView {
public _onViewControllerShown(viewController: UIViewController) {
// This method could be called with the moreNavigationController or its list controller, so we have to check.
if (trace.enabled) {
trace.write("TabView._onViewControllerShown(" + viewController + ");", trace.categories.Debug);
if (traceEnabled) {
traceWrite("TabView._onViewControllerShown(" + viewController + ");", traceCategories.Debug);
}
if (this._ios.viewControllers.containsObject(viewController)) {
this.selectedIndex = this._ios.viewControllers.indexOfObject(viewController);
}
else {
if (trace.enabled) {
trace.write("TabView._onViewControllerShown: viewController is not one of our viewControllers", trace.categories.Debug);
if (traceEnabled) {
traceWrite("TabView._onViewControllerShown: viewController is not one of our viewControllers", traceCategories.Debug);
}
}
}
private _actionBarHiddenByTabView: boolean;
public _handleTwoNavigationBars(backToMoreWillBeVisible: boolean){
if (trace.enabled) {
trace.write(`TabView._handleTwoNavigationBars(backToMoreWillBeVisible: ${backToMoreWillBeVisible})`, trace.categories.Debug);
public _handleTwoNavigationBars(backToMoreWillBeVisible: boolean) {
if (traceEnabled) {
traceWrite(`TabView._handleTwoNavigationBars(backToMoreWillBeVisible: ${backToMoreWillBeVisible})`, traceCategories.Debug);
}
// The "< Back" and "< More" navigation bars should not be visible simultaneously.
let page = <Page>this.page;
let actionBarVisible = page.frame._getNavBarVisible(page);
if (backToMoreWillBeVisible && actionBarVisible){
if (backToMoreWillBeVisible && actionBarVisible) {
page.frame.ios._disableNavBarAnimation = true;
page.actionBarHidden = true;
page.frame.ios._disableNavBarAnimation = false;
this._actionBarHiddenByTabView = true;
if (trace.enabled) {
trace.write(`TabView hid action bar`, trace.categories.Debug);
if (traceEnabled) {
traceWrite(`TabView hid action bar`, traceCategories.Debug);
}
return;
}
if (!backToMoreWillBeVisible && this._actionBarHiddenByTabView){
if (!backToMoreWillBeVisible && this._actionBarHiddenByTabView) {
page.frame.ios._disableNavBarAnimation = true;
page.actionBarHidden = false;
page.frame.ios._disableNavBarAnimation = false;
this._actionBarHiddenByTabView = undefined;
if (trace.enabled) {
trace.write(`TabView restored action bar`, trace.categories.Debug);
if (traceEnabled) {
traceWrite(`TabView restored action bar`, traceCategories.Debug);
}
return;
}
}
public _removeTabs(oldItems: Array<definition.TabViewItem>) {
if (trace.enabled) {
trace.write("TabView._removeTabs(" + oldItems + ");", trace.categories.Debug);
public _removeTabs(oldItems: Array<TabViewItem>) {
if (traceEnabled) {
traceWrite("TabView._removeTabs(" + oldItems + ");", traceCategories.Debug);
}
super._removeTabs(oldItems);
var i: number;
var length = oldItems.length;
var oldItem: TabViewItem;
for (i = 0; i < length; i++) {
oldItem = <TabViewItem>oldItems[i];
for (let i = 0, length = oldItems.length; i < length; i++) {
let oldItem = oldItems[i];
oldItem._parent = null;
oldItem._controller = null;
}
@ -246,22 +252,19 @@ export class TabView extends common.TabView {
this._ios.viewControllers = null;
}
public _addTabs(newItems: Array<definition.TabViewItem>) {
if (trace.enabled) {
trace.write("TabView._addTabs(" + newItems + ");", trace.categories.Debug);
public _addTabs(newItems: Array<TabViewItem>) {
if (traceEnabled) {
traceWrite("TabView._addTabs(" + newItems + ");", traceCategories.Debug);
}
super._addTabs(newItems);
var i: number;
var length = newItems.length;
var item: TabViewItem;
var newControllers: NSMutableArray<any> = NSMutableArray.alloc().initWithCapacity(length);
var newController: UIViewController;
const length = newItems.length;
const newControllers: NSMutableArray<any> = NSMutableArray.alloc().initWithCapacity(length);
const states = getTitleAttributesForStates(this);
var states = getTitleAttributesForStates(this);
for (i = 0; i < length; i++) {
item = <TabViewItem>newItems[i];
for (let i = 0; i < length; i++) {
const item = <TabViewItem>newItems[i];
let newController: UIViewController;
if (item.view.ios instanceof UIViewController) {
newController = <UIViewController>item.view.ios;
@ -273,16 +276,11 @@ export class TabView extends common.TabView {
item._parent = this;
item._controller = newController;
var icon = this._getIcon(item.iconSource);
const icon = this._getIcon(item.iconSource);
var tabBarItem = UITabBarItem.alloc().initWithTitleImageTag((item.title || ""), icon, i);
const tabBarItem = UITabBarItem.alloc().initWithTitleImageTag((item.title || ""), icon, i);
if (!icon) {
if (types.isFunction((<any>tabBarItem).setTitlePositionAdjustment)) {
(<any>tabBarItem).setTitlePositionAdjustment({ horizontal: 0, vertical: -20 });
}
else {
(<any>tabBarItem).titlePositionAdjustment = { horizontal: 0, vertical: -20 };
}
updateItemTitlePosition(tabBarItem);
}
tabBarItem.setTitleTextAttributesForState(states.normalState, UIControlState.Normal);
tabBarItem.setTitleTextAttributesForState(states.selectedState, UIControlState.Selected);
@ -337,14 +335,11 @@ export class TabView extends common.TabView {
return null;
}
var image: UIImage;
image = this._iconsCache[iconSource];
let image: UIImage = this._iconsCache[iconSource];
if (!image) {
ensureImageSource();
var is = imageSource.fromFileOrResource(iconSource);
const is = fromFileOrResource(iconSource);
if (is && is.ios) {
var originalRenderedImage = is.ios.imageWithRenderingMode(this._getIconRenderingMode());
const originalRenderedImage = is.ios.imageWithRenderingMode(this._getIconRenderingMode());
this._iconsCache[iconSource] = originalRenderedImage;
image = originalRenderedImage;
}
@ -357,15 +352,15 @@ export class TabView extends common.TabView {
super._onSelectedIndexPropertyChangedSetNativeValue(data);
var newIndex = data.newValue;
if (trace.enabled) {
trace.write("TabView._onSelectedIndexPropertyChangedSetNativeValue(" + newIndex + ")", trace.categories.Debug);
if (traceEnabled) {
traceWrite("TabView._onSelectedIndexPropertyChangedSetNativeValue(" + newIndex + ")", traceCategories.Debug);
}
if (types.isNullOrUndefined(newIndex)) {
return;
}
this._ios.selectedIndex = data.newValue;
// We will need to measure and arrange what became this._selectedView
this.requestLayout();
@ -374,37 +369,38 @@ export class TabView extends common.TabView {
}
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
var nativeView = this._nativeView;
const nativeView = this._nativeView;
if (nativeView) {
var width = utils.layout.getMeasureSpecSize(widthMeasureSpec);
var widthMode = utils.layout.getMeasureSpecMode(widthMeasureSpec);
const width = layout.getMeasureSpecSize(widthMeasureSpec);
const widthMode = layout.getMeasureSpecMode(widthMeasureSpec);
var height = utils.layout.getMeasureSpecSize(heightMeasureSpec);
var heightMode = utils.layout.getMeasureSpecMode(heightMeasureSpec);
const height = layout.getMeasureSpecSize(heightMeasureSpec);
const heightMode = layout.getMeasureSpecMode(heightMeasureSpec);
this._tabBarHeight = TabView.measureHelper(this._ios.tabBar, width, widthMode, height, heightMode).height;
let moreNavBarVisible = !!this._ios.moreNavigationController.navigationBar.window;
this._navBarHeight = moreNavBarVisible ? TabView.measureHelper(this._ios.moreNavigationController.navigationBar, width, widthMode, height, heightMode).height : 0;
var density = utils.layout.getDisplayDensity();
var measureWidth = 0;
var measureHeight = 0;
const density = layout.getDisplayDensity();
let measureWidth = 0;
let measureHeight = 0;
var child = this._selectedView;
const child = this._selectedView;
if (child) {
var childHeightMeasureSpec = utils.layout.makeMeasureSpec(height - this._navBarHeight - this._tabBarHeight, heightMode);
var childSize = view.View.measureChild(this, child, widthMeasureSpec, childHeightMeasureSpec);
const childHeightMeasureSpec = layout.makeMeasureSpec(height - this._navBarHeight - this._tabBarHeight, heightMode);
const childSize = View.measureChild(this, child, widthMeasureSpec, childHeightMeasureSpec);
measureHeight = childSize.measuredHeight;
measureWidth = childSize.measuredWidth;
}
measureWidth = Math.max(measureWidth, this.minWidth * density);
measureHeight = Math.max(measureHeight, this.minHeight * density);
let style = this.style;
measureWidth = Math.max(measureWidth, style.effectiveMinWidth * density);
measureHeight = Math.max(measureHeight, style.effectiveMinHeight * density);
var widthAndState = view.View.resolveSizeAndState(measureWidth, width, widthMode, 0);
var heightAndState = view.View.resolveSizeAndState(measureHeight, height, heightMode, 0);
const widthAndState = View.resolveSizeAndState(measureWidth, width, widthMode, 0);
const heightAndState = View.resolveSizeAndState(measureHeight, height, heightMode, 0);
this.setMeasuredDimension(widthAndState, heightAndState);
}
@ -413,16 +409,16 @@ export class TabView extends common.TabView {
public onLayout(left: number, top: number, right: number, bottom: number): void {
super.onLayout(left, top, right, bottom);
var child = this._selectedView;
const child = this._selectedView;
if (child) {
view.View.layoutChild(this, child, 0, this._navBarHeight, right, (bottom - this._navBarHeight - this._tabBarHeight));
View.layoutChild(this, child, 0, this._navBarHeight, right, (bottom - this._navBarHeight - this._tabBarHeight));
}
}
private static measureHelper(nativeView: UIView, width: number, widthMode: number, height: number, heightMode: number): CGSize {
return nativeView.sizeThatFits(CGSizeMake(
(widthMode === utils.layout.UNSPECIFIED) ? Number.POSITIVE_INFINITY : width,
(heightMode === utils.layout.UNSPECIFIED) ? Number.POSITIVE_INFINITY : height));
(widthMode === layout.UNSPECIFIED) ? Number.POSITIVE_INFINITY : width,
(heightMode === layout.UNSPECIFIED) ? Number.POSITIVE_INFINITY : height));
}
public _updateIOSTabBarColorsAndFonts(): void {
@ -430,10 +426,13 @@ export class TabView extends common.TabView {
return;
}
var tabBar = this.ios.tabBar;
var states = getTitleAttributesForStates(this);
for (var i = 0; i < tabBar.items.count; i++) {
var item = <UITabBarItem>tabBar.items[i];
const tabBar = this.ios.tabBar;
tabBar.tintColor = this.selectedColor ? this.selectedColor.ios : null;
const states = getTitleAttributesForStates(this);
for (let i = 0; i < tabBar.items.count; i++) {
const item = <UITabBarItem>tabBar.items[i];
item.setTitleTextAttributesForState(states.normalState, UIControlState.Normal);
item.setTitleTextAttributesForState(states.selectedState, UIControlState.Selected);
}
@ -459,21 +458,21 @@ export class TabView extends common.TabView {
}
function getTitleAttributesForStates(tabView: TabView): { normalState: any, selectedState: any } {
var normalState = {};
if (tabView.tabTextColor instanceof color.Color) {
const normalState = {};
if (tabView.tabTextColor instanceof Color) {
normalState[UITextAttributeTextColor] = tabView.tabTextColor.ios;
}
var selectedState = {};
if (tabView.selectedTabTextColor instanceof color.Color) {
const selectedState = {};
if (tabView.selectedTabTextColor instanceof Color) {
selectedState[UITextAttributeTextColor] = tabView.selectedTabTextColor.ios;
}
else {
selectedState[UITextAttributeTextColor] = tabView.ios.tabBar.tintColor;
}
var defaultFont = UIFont.systemFontOfSize(10);
var font = (<any>tabView.style)._fontInternal.getUIFont(defaultFont);
const defaultFont = UIFont.systemFontOfSize(10);
const font = (<any>tabView.style)._fontInternal.getUIFont(defaultFont);
normalState[NSFontAttributeName] = font;
selectedState[NSFontAttributeName] = font;
@ -596,4 +595,4 @@ export class TabViewStyler implements style.Styler {
}
}
TabViewStyler.registerHandlers();
TabViewStyler.registerHandlers();

View File

@ -1,6 +1,6 @@
import dts = require("utils/utils");
import common = require("./utils-common");
import {Color} from "color";
import { Color } from "color";
import enums = require("ui/enums");
import * as fsModule from "file-system";
import * as traceModule from "trace";
@ -56,9 +56,9 @@ export module ios {
}
}
export function getter<T>(_this: any, property: T | {(): T}): T {
export function getter<T>(_this: any, property: T | { (): T }): T {
if (typeof property === "function") {
return (<{(): T}>property).call(_this);
return (<{ (): T }>property).call(_this);
} else {
return <T>property;
}