Files
NativeScript/tns-core-modules/ui/action-bar/action-bar-common.ts
Hristo Hristov af034089ca iOS Frame, Page and TabView measure/layout methods removed. We now rely on the framework positioning. This will result in a change that width, height, minWidth, minHeight, margins not respected on these controls
iOS layout positioning now respects native properties like automaticallyAdjustsScrollViewInsets, edgesForExtendedLayout, extendedLayoutIncludesOpaqueBars, navigationBar.translucent, tabBar.translucent
Removed frame-tests.ios.ts - those tests are now invalid
Added new layout tests inside page-tests.ios.ts
Commented few asserts in scroll-view-tests
View now expose ios namespace with layoutView method and UILayoutViewController used by page, tab-view and application module
ViewBase now expose viewController property that should be set from all widgets that are using viewcontrollers internally (like Page, Frame, TabView)
ViewBase now sets ios property to either the view returned from createNativeView or to nativeViewProptected
fragment.transitions now use animation/transition start to add fragments to waitingQueue. Before we did it manually in navigate/goBack. This way we can reuse the fragment.transition when calling showDialog. Also when animation/transition ends we check the animation/transition to see if this fragment should be set as current.
Frame expose new loadViewFromEntry method (to load a view from URI)
Frame navigation happens once frame is loaded
Frame now supports Page as a child in XML
Fixed GridLayout row, rowSpan, column, columnSpan properties type
Fixed bug in GridLayout where add/remove of columns/rows won't update the internal state of the grid (backport from android when GridLayout is recycled)
ListView will no longer invalidate layout when cell is removed
Fixed bug in ScrollView ios where effectiveMinWidth/Height was multiplied to density (it is already on device pixels so no need to multiply)
TabView android now calls loaded only on the selected child (not all)
Core refactoring
2017-12-15 13:06:34 +02:00

337 lines
9.3 KiB
TypeScript

import {
ActionBar as ActionBarDefinition,
ActionItems as ActionItemsDefinition,
ActionItem as ActionItemDefinition,
NavigationButton, IOSActionItemSettings, AndroidActionItemSettings, AndroidActionBarSettings
} from ".";
import { profile } from "../../profiling";
export * from "../core/view";
import { View, ViewBase, Property, unsetValue, booleanConverter, horizontalAlignmentProperty, verticalAlignmentProperty } from "../core/view";
export module knownCollections {
export var actionItems = "actionItems";
}
export class ActionBarBase extends View implements ActionBarDefinition {
private _actionItems: ActionItems;
private _navigationButton: NavigationButton;
private _titleView: View;
public title: string;
public flat: boolean;
get navigationButton(): NavigationButton {
return this._navigationButton;
}
set navigationButton(value: NavigationButton) {
if (this._navigationButton !== value) {
if (this._navigationButton) {
this._removeView(this._navigationButton);
this._navigationButton.actionBar = undefined;
}
this._navigationButton = value;
if (this._navigationButton) {
this._navigationButton.actionBar = this;
this._addView(this._navigationButton);
}
this.update();
}
}
get actionItems(): ActionItems {
return this._actionItems;
}
set actionItems(value: ActionItems) {
throw new Error("actionItems property is read-only");
}
get titleView(): View {
return this._titleView;
}
set titleView(value: View) {
if (this._titleView !== value) {
if (this._titleView) {
this._removeView(this._titleView);
this._titleView.style[horizontalAlignmentProperty.cssName] = unsetValue;
this._titleView.style[verticalAlignmentProperty.cssName] = unsetValue;
}
this._titleView = value;
if (value) {
// Addview will reset CSS properties so we first add it then set aligments with lowest priority.
this._addView(value);
const style = value.style;
if (!horizontalAlignmentProperty.isSet(style)) {
style[horizontalAlignmentProperty.cssName] = "center";
}
if (!verticalAlignmentProperty.isSet(style)) {
style[verticalAlignmentProperty.cssName] = "middle";
}
}
this.update();
}
}
get android(): AndroidActionBarSettings {
return undefined;
}
get _childrenCount(): number {
let actionViewsCount = 0;
this._actionItems.getItems().forEach((actionItem) => {
if (actionItem.actionView) {
actionViewsCount++;
}
});
return actionViewsCount + (this.titleView ? 1 : 0);
}
constructor() {
super();
this._actionItems = new ActionItems(this);
}
public static onTitleChanged;
public update() {
//
}
public _onTitlePropertyChanged() {
//
}
public _addArrayFromBuilder(name: string, value: Array<any>) {
if (name === "actionItems") {
this.actionItems.setItems(value);
}
}
public eachChildView(callback: (child: View) => boolean) {
const titleView = this.titleView;
if (titleView) {
callback(titleView);
}
}
public eachChild(callback: (child: ViewBase) => boolean) {
const titleView = this.titleView;
if (titleView) {
callback(titleView);
}
const navigationButton = this._navigationButton;
if (navigationButton) {
callback(navigationButton);
}
this.actionItems.getItems().forEach((actionItem) => {
callback(actionItem);
});
}
public _isEmpty(): boolean {
if (this.title ||
this.titleView ||
(this.android && this.android.icon) ||
this.navigationButton ||
this.actionItems.getItems().length > 0) {
return false;
}
return true;
}
}
export class ActionItems implements ActionItemsDefinition {
private _items = new Array<ActionItemDefinition>();
private _actionBar: ActionBarDefinition;
constructor(actionBar: ActionBarDefinition) {
this._actionBar = actionBar;
}
public addItem(item: ActionItemDefinition): void {
if (!item) {
throw new Error("Cannot add empty item");
}
this._items.push(item);
item.actionBar = this._actionBar;
this._actionBar._addView(item);
this.invalidate();
}
public removeItem(item: ActionItemDefinition): void {
if (!item) {
throw new Error("Cannot remove empty item");
}
const itemIndex = this._items.indexOf(item);
if (itemIndex < 0) {
throw new Error("Cannot find item to remove");
}
this._items.splice(itemIndex, 1);
this._actionBar._removeView(item);
item.actionBar = undefined;
this.invalidate();
}
public getItems(): Array<ActionItemDefinition> {
return this._items.slice();
}
public getVisibleItems(): Array<ActionItemDefinition> {
const visibleItems = [];
this._items.forEach((item) => {
if (isVisible(item)) {
visibleItems.push(item);
}
});
return visibleItems;
}
public getItemAt(index: number): ActionItemDefinition {
if (index < 0 || index >= this._items.length) {
return undefined;
}
return this._items[index];
}
public setItems(items: Array<ActionItemDefinition>) {
// Remove all existing items
while (this._items.length > 0) {
this.removeItem(this._items[this._items.length - 1]);
}
// Add new items
for (var i = 0; i < items.length; i++) {
this.addItem(items[i]);
}
this.invalidate();
}
private invalidate() {
if (this._actionBar) {
this._actionBar.update();
}
}
}
export class ActionItemBase extends ViewBase implements ActionItemDefinition {
public static tapEvent = "tap";
private _actionBar: ActionBarDefinition;
private _actionView: View;
public ios: IOSActionItemSettings;
public android: AndroidActionItemSettings;
public text: string;
public icon: string;
public visibility: string;
get actionView(): View {
return this._actionView;
}
set actionView(value: View) {
if (this._actionView !== value) {
if (this._actionView) {
this._actionView.style[horizontalAlignmentProperty.cssName] = unsetValue;
this._actionView.style[verticalAlignmentProperty.cssName] = unsetValue;
this._removeView(this._actionView);
}
this._actionView = value;
if (this._actionView) {
this._addView(this._actionView);
}
if (this._actionBar) {
this._actionBar.update();
}
}
}
get actionBar(): ActionBarDefinition {
return this._actionBar;
}
set actionBar(value: ActionBarDefinition) {
if (value !== this._actionBar) {
this._actionBar = value;
}
}
@profile
public onLoaded() {
if (this._actionView) {
this._actionView.style[horizontalAlignmentProperty.cssName] = "center";
this._actionView.style[verticalAlignmentProperty.cssName] = "middle";
}
super.onLoaded();
}
public _raiseTap() {
this._emit(ActionItemBase.tapEvent);
}
public _addChildFromBuilder(name: string, value: any) {
this.actionView = value;
}
public eachChild(callback: (child: ViewBase) => boolean) {
if (this._actionView) {
callback(this._actionView);
}
}
}
export function isVisible(item: ActionItemDefinition) {
return item.visibility === "visible";
}
function onTitlePropertyChanged(actionBar: ActionBarBase, oldValue: string, newValue: string) {
actionBar._onTitlePropertyChanged();
}
export const titleProperty = new Property<ActionBarBase, string>({ name: "title", valueChanged: onTitlePropertyChanged });
titleProperty.register(ActionBarBase);
function onItemChanged(item: ActionItemBase, oldValue: string, newValue: string) {
if (item.actionBar) {
item.actionBar.update();
}
}
export const textProperty = new Property<ActionItemBase, string>({ name: "text", defaultValue: "", valueChanged: onItemChanged });
textProperty.register(ActionItemBase);
export const iconProperty = new Property<ActionItemBase, string>({ name: "icon", valueChanged: onItemChanged });
iconProperty.register(ActionItemBase);
export const visibilityProperty = new Property({ name: "visibility", defaultValue: "visible", valueChanged: onItemChanged });
visibilityProperty.register(ActionItemBase);
export const flatProperty = new Property<ActionBarBase, boolean>({ name: "flat", defaultValue: false, valueConverter: booleanConverter });
flatProperty.register(ActionBarBase);