Layouts are now implemented natively for Android.

This commit is contained in:
hshristov
2015-07-16 01:22:16 +03:00
parent 5a06731daa
commit 0ad198165c
45 changed files with 1727 additions and 1187 deletions

View File

@@ -527,6 +527,62 @@
<TypeScriptCompile Include="ui\html-view\html-view.android.ts" />
<TypeScriptCompile Include="ui\html-view\html-view.d.ts" />
<TypeScriptCompile Include="ui\html-view\html-view.ios.ts" />
<TypeScriptCompile Include="org.nativescript.widgets.d.ts" />
<TypeScriptCompile Include="ui\layouts\absolute-layout\absolute-layout-common.ts">
<DependentUpon>absolute-layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\absolute-layout\absolute-layout.ios.ts">
<DependentUpon>absolute-layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\absolute-layout\absolute-layout.android.ts">
<DependentUpon>absolute-layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\dock-layout\dock-layout.ios.ts">
<DependentUpon>dock-layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\dock-layout\dock-layout.android.ts">
<DependentUpon>dock-layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\dock-layout\dock-layout-common.ts">
<DependentUpon>dock-layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\grid-layout\grid-layout-common.ts">
<DependentUpon>grid-layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\grid-layout\grid-layout.android.ts">
<DependentUpon>grid-layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\grid-layout\grid-layout.ios.ts">
<DependentUpon>grid-layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\layout.ios.ts">
<DependentUpon>layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\layout.android.ts">
<DependentUpon>layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\layout-base.ts">
<DependentUpon>layout-base.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\layout-base.d.ts" />
<TypeScriptCompile Include="ui\layouts\stack-layout\stack-layout.ios.ts">
<DependentUpon>stack-layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\stack-layout\stack-layout.android.ts">
<DependentUpon>stack-layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\stack-layout\stack-layout-common.ts">
<DependentUpon>stack-layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\wrap-layout\wrap-layout-common.ts">
<DependentUpon>wrap-layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\wrap-layout\wrap-layout.android.ts">
<DependentUpon>wrap-layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\wrap-layout\wrap-layout.ios.ts">
<DependentUpon>wrap-layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\repeater\repeater.ts">
<DependentUpon>repeater.d.ts</DependentUpon>
</TypeScriptCompile>
@@ -588,26 +644,11 @@
<TypeScriptCompile Include="ui\image-cache\image-cache.ios.ts">
<DependentUpon>image-cache.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\absolute-layout\absolute-layout.ts">
<DependentUpon>absolute-layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\dock-layout\dock-layout.ts">
<DependentUpon>dock-layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\grid-layout\grid-layout.ts">
<DependentUpon>grid-layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\layout.ts">
<DependentUpon>layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\layout.d.ts" />
<TypeScriptCompile Include="ui\layouts\absolute-layout\absolute-layout.d.ts" />
<TypeScriptCompile Include="ui\layouts\wrap-layout\wrap-layout.d.ts" />
<TypeScriptCompile Include="ui\layouts\grid-layout\grid-layout.d.ts" />
<TypeScriptCompile Include="ui\layouts\dock-layout\dock-layout.d.ts" />
<TypeScriptCompile Include="ui\layouts\stack-layout\stack-layout.ts">
<DependentUpon>stack-layout.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\layouts\stack-layout\stack-layout.d.ts" />
<TypeScriptCompile Include="ui\layouts\wrap-layout\wrap-layout.ts">
<DependentUpon>wrap-layout.d.ts</DependentUpon>

View File

@@ -3,12 +3,9 @@ import slider = require("ui/slider");
import imageSource = require("image-source");
import gridModule = require("ui/layouts/grid-layout");
import enums = require("ui/enums");
import img = require("ui/image");
var Image = img.Image;
export function createPage() {
var StackLayout = require("ui/layouts/stack-layout").StackLayout;
var Image = require("ui/image").Image;
var stack = new StackLayout();
var grid = new gridModule.GridLayout();
grid.addColumn(new gridModule.ItemSpec(1, gridModule.GridUnitType.auto));
@@ -17,24 +14,16 @@ export function createPage() {
grid.addRow(new gridModule.ItemSpec(1, gridModule.GridUnitType.auto));
grid.addRow(new gridModule.ItemSpec(1, gridModule.GridUnitType.star));
var sldr = new slider.Slider();
gridModule.GridLayout.setColumnSpan(sldr, 2);
sldr.maxValue = 500;
stack.addChild(sldr);
stack.addChild(grid);
var image = new Image();
image.stretch = enums.Stretch.fill;
image.verticalAlignment = 2;
image.horizontalAlignment = 1;
image.verticalAlignment = enums.VerticalAlignment.bottom;
image.horizontalAlignment = enums.HorizontalAlignment.center;
image.source = imageSource.fromFile(__dirname + "test.png");
image.imageSource = imageSource.fromFile(__dirname + "/test.png");
grid.addChild(image);
var page = new pages.Page();
page.content = stack;
page.content = grid;
page.css = "GridLayout { background-color: pink } image { background-color: green }";
return page;
}
//export var Page = page;
}

View File

@@ -1,7 +1,7 @@
import observable = require("data/observable");
import enums = require("ui/enums");
import view = require("ui/core/view");
import layouts = require("ui/layouts/layout");
import layouts = require("ui/layouts/layout-base");
export class ViewModel extends observable.Observable {
@@ -67,7 +67,7 @@ export class ViewModel extends observable.Observable {
public onVisibile(args: { eventName: string, object: any }): void {
var view: view.View = <view.View>args.object;
var layout = <layouts.Layout>view.parent;
var layout = <layouts.LayoutBase>view.parent;
var child = layout.getViewById("collapse");
child.visibility = enums.Visibility.visible;

View File

@@ -47,6 +47,7 @@ export class ContentView extends view.CustomLayoutView implements definition.Con
}
}
// This method won't be called in Android because we use the native android layout.
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
var result = view.View.measureChild(this, this.content, widthMeasureSpec, heightMeasureSpec);
@@ -66,6 +67,7 @@ export class ContentView extends view.CustomLayoutView implements definition.Con
this.setMeasuredDimension(widthAndState, heightAndState);
}
// This method won't be called in Android because we use the native android layout.
public onLayout(left: number, top: number, right: number, bottom: number): void {
view.View.layoutChild(this, this.content, 0, 0, right - left, bottom - top);
}

View File

@@ -68,7 +68,7 @@ export class PropertyMetadata implements definition.PropertyMetadata {
equalityComparer?: definition.PropertyEqualityComparer) {
this._defaultValue = defaultValue;
this._options = options;
if (types.isUndefined(this._options)) {
if (types.isNullOrUndefined(this._options)) {
this._options = PropertyMetadataSettings.None;
}
this._onChanged = onChanged;

View File

@@ -128,6 +128,7 @@ export class View extends proxy.ProxyObject implements definition.View {
private _requestedVisualState: string;
private _isLoaded: boolean;
private _isLayoutValid: boolean = false;
public _domId: number;
public _isAddedToNativeVisualTree = false;
@@ -293,41 +294,6 @@ export class View extends proxy.ProxyObject implements definition.View {
this.style.marginBottom = value;
}
get padding(): string {
return this.style.padding;
}
set padding(value: string) {
this.style.padding = value;
}
get paddingLeft(): number {
return this.style.paddingLeft;
}
set paddingLeft(value: number) {
this.style.paddingLeft = value;
}
get paddingTop(): number {
return this.style.paddingTop;
}
set paddingTop(value: number) {
this.style.paddingTop = value;
}
get paddingRight(): number {
return this.style.paddingRight;
}
set paddingRight(value: number) {
this.style.paddingRight = value;
}
get paddingBottom(): number {
return this.style.paddingBottom;
}
set paddingBottom(value: number) {
this.style.paddingBottom = value;
}
get horizontalAlignment(): string {
return this.style.horizontalAlignment;
}
@@ -510,11 +476,11 @@ export class View extends proxy.ProxyObject implements definition.View {
}
public getMeasuredWidth(): number {
return this._measuredWidth;
return this._measuredWidth & utils.layout.MEASURED_SIZE_MASK;
}
public getMeasuredHeight(): number {
return this._measuredHeight;
return this._measuredHeight & utils.layout.MEASURED_SIZE_MASK;
}
public setMeasuredDimension(measuredWidth: number, measuredHeight: number): void {

View File

@@ -32,16 +32,13 @@ function onIsUserInteractionEnabledPropertyChanged(data: dependencyObservable.Pr
(<proxy.PropertyMetadata>viewCommon.View.isUserInteractionEnabledProperty.metadata).onSetNativeValue = onIsUserInteractionEnabledPropertyChanged;
export var NativeViewGroup = (<any>android.view.ViewGroup).extend({
get owner() {
return this[OWNER];
},
onMeasure: function (widthMeasureSpec, heightMeasureSpec) {
var owner: viewDefinition.View = this.owner;
var owner: viewDefinition.View = this[OWNER];
owner.onMeasure(widthMeasureSpec, heightMeasureSpec);
this.setMeasuredDimension(owner.getMeasuredWidth(), owner.getMeasuredHeight());
},
onLayout: function (changed: boolean, left: number, top: number, right: number, bottom: number): void {
var owner: viewDefinition.View = this.owner;
var owner: viewDefinition.View = this[OWNER];
owner.onLayout(left, top, right, bottom);
}
});
@@ -239,6 +236,14 @@ export class View extends viewCommon.View {
return this.android;
}
get isLayoutValid(): boolean {
if (this._nativeView) {
return !this._nativeView.isLayoutRequested();
}
return false;
}
public layoutNativeView(left: number, top: number, right: number, bottom: number): void {
if (this._nativeView) {
this._nativeView.layout(left, top, right, bottom);
@@ -287,8 +292,8 @@ export class View extends viewCommon.View {
}
public focus(): boolean {
if (this.android) {
return this.android.requestFocus();
if (this._nativeView) {
return this._nativeView.requestFocus();
}
return false;
@@ -328,15 +333,9 @@ export class CustomLayoutView extends View implements viewDefinition.CustomLayou
}
public _createUI() {
this._viewGroup = new NativeViewGroup(this._context);
this._viewGroup[OWNER] = this;
this._viewGroup = new org.nativescript.widgets.ContentLayout(this._context);
}
//public _onDetached(force?: boolean) {
// delete this._viewGroup[OWNER];
// super._onDetached(force);
//}
public _addViewToNativeVisualTree(child: View): boolean {
super._addViewToNativeVisualTree(child);
@@ -356,46 +355,4 @@ export class CustomLayoutView extends View implements viewDefinition.CustomLayou
trace.notifyEvent(child, "childInLayoutRemovedFromNativeVisualTree");
}
}
public measure(widthMeasureSpec: number, heightMeasureSpec: number): void {
this._setCurrentMeasureSpecs(widthMeasureSpec, heightMeasureSpec);
var view = this._nativeView;
if (view) {
var width = utils.layout.getMeasureSpecSize(widthMeasureSpec);
var widthMode = utils.layout.getMeasureSpecMode(widthMeasureSpec);
var height = utils.layout.getMeasureSpecSize(heightMeasureSpec);
var heightMode = utils.layout.getMeasureSpecMode(heightMeasureSpec);
trace.write(this + " :measure: " + utils.layout.getMode(widthMode) + " " + width + ", " + utils.layout.getMode(heightMode) + " " + height, trace.categories.Layout);
view.measure(widthMeasureSpec, heightMeasureSpec);
}
}
public layout(left: number, top: number, right: number, bottom: number): void {
this._setCurrentLayoutBounds(left, top, right, bottom);
var view = this._nativeView;
if (view) {
this.layoutNativeView(left, top, right, bottom);
trace.write(this + " :layout: " + left + ", " + top + ", " + (right - left) + ", " + (bottom - top), trace.categories.Layout);
}
}
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
// Don't call super because it will trigger measure again.
var width = utils.layout.getMeasureSpecSize(widthMeasureSpec);
var widthMode = utils.layout.getMeasureSpecMode(widthMeasureSpec);
var height = utils.layout.getMeasureSpecSize(heightMeasureSpec);
var heightMode = utils.layout.getMeasureSpecMode(heightMeasureSpec);
trace.write(this + " :onMeasure: " + utils.layout.getMode(widthMode) + " " + width + ", " + utils.layout.getMode(heightMode) + " " + height, trace.categories.Layout);
}
public onLayout(left: number, top: number, right: number, bottom: number): void {
// Don't call super because it will trigger layout again.
trace.write(this + " :onLayout: " + left + ", " + top + ", " + (right - left) + ", " + (bottom - top), trace.categories.Layout);
}
}

25
ui/core/view.d.ts vendored
View File

@@ -205,31 +205,6 @@ declare module "ui/core/view" {
*/
marginBottom: number;
/**
* Gets or sets padding style property.
*/
padding: string;
/**
* Specify the left padding of this view.
*/
paddingLeft: number;
/**
* Specify the top padding of this view.
*/
paddingTop: number;
/**
* Specify the right padding of this view.
*/
paddingRight: number;
/**
* Specify the bottom padding of this view.
*/
paddingBottom: number;
/**
* Gets or sets the alignment of this view within its parent along the Horizontal axis.
*/

View File

@@ -85,13 +85,18 @@ export class View extends viewCommon.View {
// For UILabel and UIImage.
view.userInteractionEnabled = true;
}
get isLayoutRequested(): boolean {
return (this._privateFlags & PFLAG_FORCE_LAYOUT) === PFLAG_FORCE_LAYOUT;
}
public requestLayout(): void {
super.requestLayout();
this._privateFlags |= PFLAG_FORCE_LAYOUT;
if (this.parent) {
this.parent.requestLayout();
var parent = <View>this.parent;
if (parent && !parent.isLayoutRequested) {
parent.requestLayout();
}
}
@@ -236,7 +241,7 @@ export class CustomLayoutView extends View {
}
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
// Don't call super because it will trigger measure again.
// Don't call super because it will set MeasureDimension. This method must be overriden and calculate its measuredDimensions.
var width = utils.layout.getMeasureSpecSize(widthMeasureSpec);
var widthMode = utils.layout.getMeasureSpecMode(widthMeasureSpec);

View File

@@ -327,25 +327,6 @@ export class Frame extends view.CustomLayoutView implements definition.Frame {
return 0;
}
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
var width = utils.layout.getMeasureSpecSize(widthMeasureSpec);
var widthMode = utils.layout.getMeasureSpecMode(widthMeasureSpec);
var height = utils.layout.getMeasureSpecSize(heightMeasureSpec);
var heightMode = utils.layout.getMeasureSpecMode(heightMeasureSpec);
var result = view.View.measureChild(this, this.currentPage, widthMeasureSpec, utils.layout.makeMeasureSpec(height - this.navigationBarHeight, heightMode));
var widthAndState = view.View.resolveSizeAndState(result.measuredWidth, width, widthMode, 0);
var heightAndState = view.View.resolveSizeAndState(result.measuredHeight, height, heightMode, 0);
this.setMeasuredDimension(widthAndState, heightAndState);
}
public onLayout(left: number, top: number, right: number, bottom: number): void {
view.View.layoutChild(this, this.currentPage, 0, this.navigationBarHeight, right - left, bottom - top);
}
// We don't need to put Page as visual child. Don't call super.
public _addViewToNativeVisualTree(child: view.View): boolean {
return true;

View File

@@ -373,8 +373,7 @@ var NativeActivity = {
this.androidFrame.setActivity(this);
// Create and set content container.
var root = new view.NativeViewGroup(this);
root[OWNER] = this.frame;
var root = new org.nativescript.widgets.ContentLayout(this);
this.androidFrame.rootViewGroup = root;
this.androidFrame.rootViewGroup.setId(this.frame.containerViewId);

View File

@@ -3,9 +3,7 @@ import view = require("ui/core/view");
import proxy = require("ui/core/proxy");
import imageSource = require("image-source");
import definition = require("ui/image");
import trace = require("trace");
import enums = require("ui/enums");
import utils = require("utils/utils");
import types = require("utils/types");
var SRC = "src";
@@ -49,43 +47,18 @@ function onSrcPropertyChanged(data: dependencyObservable.PropertyChangeData) {
export class Image extends view.View implements definition.Image {
public static srcProperty = new dependencyObservable.Property(
SRC,
IMAGE,
new proxy.PropertyMetadata(
undefined,
dependencyObservable.PropertyMetadataSettings.None,
onSrcPropertyChanged
)
);
public static srcProperty = new dependencyObservable.Property(SRC, IMAGE,
new proxy.PropertyMetadata(undefined, dependencyObservable.PropertyMetadataSettings.None, onSrcPropertyChanged));
public static imageSourceProperty = new dependencyObservable.Property(
IMAGE_SOURCE,
IMAGE,
new proxy.PropertyMetadata(
undefined,
// None on purpose. for iOS we trigger it manually if needed. Android layout handles it.
dependencyObservable.PropertyMetadataSettings.None
)
);
// None on purpose. for iOS we trigger it manually if needed. Android layout handles it.
public static imageSourceProperty = new dependencyObservable.Property(IMAGE_SOURCE, IMAGE,
new proxy.PropertyMetadata(undefined, dependencyObservable.PropertyMetadataSettings.None));
public static isLoadingProperty = new dependencyObservable.Property(
ISLOADING,
IMAGE,
new proxy.PropertyMetadata(
false,
dependencyObservable.PropertyMetadataSettings.None
)
);
public static isLoadingProperty = new dependencyObservable.Property(ISLOADING, IMAGE,
new proxy.PropertyMetadata(false, dependencyObservable.PropertyMetadataSettings.None));
public static stretchProperty = new dependencyObservable.Property(
STRETCH,
IMAGE,
new proxy.PropertyMetadata(
enums.Stretch.aspectFit,
dependencyObservable.PropertyMetadataSettings.AffectsLayout
)
);
public static stretchProperty = new dependencyObservable.Property(STRETCH, IMAGE,
new proxy.PropertyMetadata(enums.Stretch.aspectFit, dependencyObservable.PropertyMetadataSettings.AffectsLayout));
constructor(options?: definition.Options) {
super(options);
@@ -119,75 +92,4 @@ export class Image extends view.View implements definition.Image {
public _setNativeImage(nativeImage: any) {
//
}
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
// We don't call super because we measure native view with specific size.
var width = utils.layout.getMeasureSpecSize(widthMeasureSpec);
var widthMode = utils.layout.getMeasureSpecMode(widthMeasureSpec);
var height = utils.layout.getMeasureSpecSize(heightMeasureSpec);
var heightMode = utils.layout.getMeasureSpecMode(heightMeasureSpec);
trace.write(this + " :onMeasure: " + utils.layout.getMode(widthMode) + " " + width + ", " + utils.layout.getMode(heightMode) + " " + height, trace.categories.Layout);
var nativeWidth = this.imageSource ? this.imageSource.width : 0;
var nativeHeight = this.imageSource ? this.imageSource.height : 0;
var measureWidth = Math.max(nativeWidth, this.minWidth);
var measureHeight = Math.max(nativeHeight, this.minHeight);
var finiteWidth: boolean = widthMode !== utils.layout.UNSPECIFIED;
var finiteHeight: boolean = heightMode !== utils.layout.UNSPECIFIED;
if (nativeWidth !== 0 && nativeHeight !== 0 && (finiteWidth || finiteHeight)) {
var scale = Image.computeScaleFactor(width, height, finiteWidth, finiteHeight, nativeWidth, nativeHeight, this.stretch);
var resultW = Math.floor(nativeWidth * scale.width);
var resultH = Math.floor(nativeHeight * scale.height);
measureWidth = finiteWidth ? Math.min(resultW, width) : resultW;
measureHeight = finiteHeight ? Math.min(resultH, height) : resultH;
trace.write("Image stretch: " + this.stretch +
", nativeWidth: " + nativeWidth +
", nativeHeight: " + nativeHeight, trace.categories.Layout);
}
var widthAndState = view.View.resolveSizeAndState(measureWidth, width, widthMode, 0);
var heightAndState = view.View.resolveSizeAndState(measureHeight, height, heightMode, 0);
this.setMeasuredDimension(widthAndState, heightAndState);
}
private static computeScaleFactor(measureWidth: number, measureHeight: number, widthIsFinite: boolean, heightIsFinite: boolean, nativeWidth: number, nativeHeight: number, imageStretch: string): { width: number; height: number } {
var scaleW = 1;
var scaleH = 1;
if ((imageStretch === enums.Stretch.aspectFill || imageStretch === enums.Stretch.aspectFit || imageStretch === enums.Stretch.fill) &&
(widthIsFinite || heightIsFinite)) {
scaleW = (nativeWidth > 0) ? measureWidth / nativeWidth : 0;
scaleH = (nativeHeight > 0) ? measureHeight / nativeHeight : 0;
if (!widthIsFinite) {
scaleW = scaleH;
}
else if (!heightIsFinite) {
scaleH = scaleW;
}
else {
// No infinite dimensions.
switch (imageStretch) {
case enums.Stretch.aspectFit:
scaleH = scaleW < scaleH ? scaleW : scaleH;
scaleW = scaleH;
break;
case enums.Stretch.aspectFill:
scaleH = scaleW > scaleH ? scaleW : scaleH;
scaleW = scaleH;
break;
}
}
}
return { width: scaleW, height: scaleH };
}
}

View File

@@ -42,14 +42,14 @@ function onImageSourcePropertyChanged(data: dependencyObservable.PropertyChangeD
(<proxy.PropertyMetadata>imageCommon.Image.stretchProperty.metadata).onSetNativeValue = onStretchPropertyChanged;
export class Image extends imageCommon.Image {
private _android: android.widget.ImageView;
private _android: org.nativescript.widgets.ImageView;
get android(): android.widget.ImageView {
get android(): org.nativescript.widgets.ImageView {
return this._android;
}
public _createUI() {
this._android = new android.widget.ImageView(this._context);
this._android = new org.nativescript.widgets.ImageView(this._context);
}
public _setNativeImage(nativeImage: any) {

View File

@@ -3,6 +3,9 @@ import dependencyObservable = require("ui/core/dependency-observable");
import proxy = require("ui/core/proxy");
import definition = require("ui/image");
import enums = require("ui/enums");
import utils = require("utils/utils");
import trace = require("trace");
import view = require("ui/core/view");
global.moduleMerge(imageCommon, exports);
@@ -59,4 +62,75 @@ export class Image extends imageCommon.Image {
this.requestLayout();
}
}
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
// We don't call super because we measure native view with specific size.
var width = utils.layout.getMeasureSpecSize(widthMeasureSpec);
var widthMode = utils.layout.getMeasureSpecMode(widthMeasureSpec);
var height = utils.layout.getMeasureSpecSize(heightMeasureSpec);
var heightMode = utils.layout.getMeasureSpecMode(heightMeasureSpec);
trace.write(this + " :onMeasure: " + utils.layout.getMode(widthMode) + " " + width + ", " + utils.layout.getMode(heightMode) + " " + height, trace.categories.Layout);
var nativeWidth = this.imageSource ? this.imageSource.width : 0;
var nativeHeight = this.imageSource ? this.imageSource.height : 0;
var measureWidth = Math.max(nativeWidth, this.minWidth);
var measureHeight = Math.max(nativeHeight, this.minHeight);
var finiteWidth: boolean = widthMode !== utils.layout.UNSPECIFIED;
var finiteHeight: boolean = heightMode !== utils.layout.UNSPECIFIED;
if (nativeWidth !== 0 && nativeHeight !== 0 && (finiteWidth || finiteHeight)) {
var scale = Image.computeScaleFactor(width, height, finiteWidth, finiteHeight, nativeWidth, nativeHeight, this.stretch);
var resultW = Math.floor(nativeWidth * scale.width);
var resultH = Math.floor(nativeHeight * scale.height);
measureWidth = finiteWidth ? Math.min(resultW, width) : resultW;
measureHeight = finiteHeight ? Math.min(resultH, height) : resultH;
trace.write("Image stretch: " + this.stretch +
", nativeWidth: " + nativeWidth +
", nativeHeight: " + nativeHeight, trace.categories.Layout);
}
var widthAndState = view.View.resolveSizeAndState(measureWidth, width, widthMode, 0);
var heightAndState = view.View.resolveSizeAndState(measureHeight, height, heightMode, 0);
this.setMeasuredDimension(widthAndState, heightAndState);
}
private static computeScaleFactor(measureWidth: number, measureHeight: number, widthIsFinite: boolean, heightIsFinite: boolean, nativeWidth: number, nativeHeight: number, imageStretch: string): { width: number; height: number } {
var scaleW = 1;
var scaleH = 1;
if ((imageStretch === enums.Stretch.aspectFill || imageStretch === enums.Stretch.aspectFit || imageStretch === enums.Stretch.fill) &&
(widthIsFinite || heightIsFinite)) {
scaleW = (nativeWidth > 0) ? measureWidth / nativeWidth : 0;
scaleH = (nativeHeight > 0) ? measureHeight / nativeHeight : 0;
if (!widthIsFinite) {
scaleW = scaleH;
}
else if (!heightIsFinite) {
scaleH = scaleW;
}
else {
// No infinite dimensions.
switch (imageStretch) {
case enums.Stretch.aspectFit:
scaleH = scaleW < scaleH ? scaleW : scaleH;
scaleW = scaleH;
break;
case enums.Stretch.aspectFill:
scaleH = scaleW > scaleH ? scaleW : scaleH;
scaleW = scaleH;
break;
}
}
}
return { width: scaleW, height: scaleH };
}
}

View File

@@ -0,0 +1,69 @@
import layouts = require("ui/layouts/layout-base");
import definition = require("ui/layouts/absolute-layout");
import dependencyObservable = require("ui/core/dependency-observable");
import view = require("ui/core/view");
import proxy = require("ui/core/proxy");
function validateArgs(element: view.View): view.View {
if (!element) {
throw new Error("element cannot be null or undefinied.");
}
return element;
}
export class AbsoluteLayout extends layouts.LayoutBase implements definition.AbsoluteLayout {
private static isValid(value: number): boolean {
return isFinite(value);
}
private static onLeftPropertyChanged(data: dependencyObservable.PropertyChangeData) {
var uiView = data.object;
if (uiView instanceof view.View) {
var layout = uiView.parent;
if (layout instanceof AbsoluteLayout) {
layout.onLeftChanged(uiView, data.oldValue, data.newValue);
}
}
}
private static onTopPropertyChanged(data: dependencyObservable.PropertyChangeData) {
var uiView = data.object;
if (uiView instanceof view.View) {
var layout = uiView.parent;
if (layout instanceof AbsoluteLayout) {
layout.onTopChanged(uiView, data.oldValue, data.newValue);
}
}
}
public static leftProperty = new dependencyObservable.Property("left", "AbsoluteLayout",
new proxy.PropertyMetadata(0, undefined, AbsoluteLayout.onLeftPropertyChanged, AbsoluteLayout.isValid));
public static topProperty = new dependencyObservable.Property("top", "AbsoluteLayout",
new proxy.PropertyMetadata(0, undefined, AbsoluteLayout.onTopPropertyChanged, AbsoluteLayout.isValid));
public static getLeft(element: view.View): number {
return validateArgs(element)._getValue(AbsoluteLayout.leftProperty);
}
public static setLeft(element: view.View, value: number): void {
validateArgs(element)._setValue(AbsoluteLayout.leftProperty, value);
}
public static getTop(element: view.View): number {
return validateArgs(element)._getValue(AbsoluteLayout.topProperty);
}
public static setTop(element: view.View, value: number): void {
validateArgs(element)._setValue(AbsoluteLayout.topProperty, value);
}
protected onLeftChanged(view: view.View, oldValue: number, newValue: number) {
//
}
protected onTopChanged(view: view.View, oldValue: number, newValue: number) {
//
}
}

View File

@@ -0,0 +1,52 @@
import utils = require("utils/utils");
import view = require("ui/core/view");
import common = require("ui/layouts/absolute-layout/absolute-layout-common");
import dependencyObservable = require("ui/core/dependency-observable");
import proxy = require("ui/core/proxy");
// merge the exports of the common file with the exports of this file
declare var exports;
require("utils/module-merge").merge(common, exports);
function setNativeProperty(data: dependencyObservable.PropertyChangeData, setter: (lp: org.nativescript.widgets.CommonLayoutParams) => void) {
var uiView = data.object;
if (uiView instanceof view.View) {
var nativeView: android.view.View = uiView._nativeView;
var lp = <org.nativescript.widgets.CommonLayoutParams>nativeView.getLayoutParams();
if (!(lp instanceof org.nativescript.widgets.CommonLayoutParams)) {
lp = new org.nativescript.widgets.CommonLayoutParams();
}
setter(lp);
nativeView.setLayoutParams(lp);
}
}
function setNativeLeftProperty(data: dependencyObservable.PropertyChangeData) {
setNativeProperty(data, (lp) => { lp.left = data.newValue * utils.layout.getDisplayDensity(); });
}
function setNativeTopProperty(data: dependencyObservable.PropertyChangeData) {
setNativeProperty(data, (lp) => { lp.top = data.newValue * utils.layout.getDisplayDensity(); });
}
(<proxy.PropertyMetadata>common.AbsoluteLayout.leftProperty.metadata).onSetNativeValue = setNativeLeftProperty;
(<proxy.PropertyMetadata>common.AbsoluteLayout.topProperty.metadata).onSetNativeValue = setNativeTopProperty;
export class AbsoluteLayout extends common.AbsoluteLayout {
private _layout: org.nativescript.widgets.AbsoluteLayout;
get android(): org.nativescript.widgets.AbsoluteLayout {
return this._layout;
}
get _nativeView(): org.nativescript.widgets.AbsoluteLayout {
return this._layout;
}
public _createUI() {
this._layout = new org.nativescript.widgets.AbsoluteLayout(this._context);
}
}

View File

@@ -1,12 +1,12 @@
declare module "ui/layouts/absolute-layout" {
import layout = require("ui/layouts/layout");
import layout = require("ui/layouts/layout-base");
import view = require("ui/core/view");
import dependencyObservable = require("ui/core/dependency-observable");
/**
* A layout that lets you specify exact locations (left/top coordinates) of its children.
*/
class AbsoluteLayout extends layout.Layout {
class AbsoluteLayout extends layout.LayoutBase {
/**
* Represents the observable property backing the left property.

View File

@@ -1,56 +1,19 @@
import layouts = require("ui/layouts/layout");
import definition = require("ui/layouts/absolute-layout");
import utils = require("utils/utils");
import dependencyObservable = require("ui/core/dependency-observable");
import utils = require("utils/utils");
import view = require("ui/core/view");
import numberUtils = require("utils/number-utils");
import common = require("ui/layouts/absolute-layout/absolute-layout-common");
function onPropertyChanged(data: dependencyObservable.PropertyChangeData) {
var uiView = data.object;
if (uiView instanceof view.View) {
var layout = uiView.parent;
if (layout instanceof AbsoluteLayout) {
layout.requestLayout();
}
}
}
// merge the exports of the common file with the exports of this file
declare var exports;
require("utils/module-merge").merge(common, exports);
export class AbsoluteLayout extends layouts.Layout implements definition.AbsoluteLayout {
export class AbsoluteLayout extends common.AbsoluteLayout {
public static leftProperty = new dependencyObservable.Property("left", "AbsoluteLayout",
new dependencyObservable.PropertyMetadata(0, undefined, onPropertyChanged, numberUtils.isFiniteNumber));
public static topProperty = new dependencyObservable.Property("top", "AbsoluteLayout",
new dependencyObservable.PropertyMetadata(0, undefined, onPropertyChanged, numberUtils.isFiniteNumber));
public static getLeft(element: view.View): number {
if (!element) {
throw new Error("element cannot be null or undefinied.");
}
return element._getValue(AbsoluteLayout.leftProperty);
protected onLeftChanged(view: view.View, oldValue: number, newValue: number) {
this.requestLayout();
}
public static setLeft(element: view.View, value: number): void {
if (!element) {
throw new Error("element cannot be null or undefinied.");
}
element._setValue(AbsoluteLayout.leftProperty, value);
}
public static getTop(element: view.View): number {
if (!element) {
throw new Error("element cannot be null or undefinied.");
}
return element._getValue(AbsoluteLayout.topProperty);
}
public static setTop(element: view.View, value: number): void {
if (!element) {
throw new Error("element cannot be null or undefinied.");
}
element._setValue(AbsoluteLayout.topProperty, value);
protected onTopChanged(view: view.View, oldValue: number, newValue: number) {
this.requestLayout();
}
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {

View File

@@ -0,0 +1,58 @@
import layouts = require("ui/layouts/layout-base");
import definition = require("ui/layouts/dock-layout");
import dependencyObservable = require("ui/core/dependency-observable");
import view = require("ui/core/view");
import enums = require("ui/enums");
import proxy = require("ui/core/proxy");
// on Android we explicitly set propertySettings to None because android will invalidate its layout (skip unnecessary native call).
var AffectsLayout = global.android ? dependencyObservable.PropertyMetadataSettings.None : dependencyObservable.PropertyMetadataSettings.AffectsLayout;
function isDockValid(value: any): boolean {
return value === enums.Dock.left || value === enums.Dock.top || value === enums.Dock.right || value === enums.Dock.bottom;
}
function validateArgs(element: view.View): view.View {
if (!element) {
throw new Error("element cannot be null or undefinied.");
}
return element;
}
export class DockLayout extends layouts.LayoutBase implements definition.DockLayout {
private static onDockPropertyChanged(data: dependencyObservable.PropertyChangeData) {
var uiView = data.object;
if (uiView instanceof view.View) {
var layout = uiView.parent;
if (layout instanceof DockLayout) {
layout.onDockChanged(uiView, data.oldValue, data.newValue);
}
}
}
public static dockProperty = new dependencyObservable.Property(
"dock", "DockLayout", new proxy.PropertyMetadata(enums.Dock.left, undefined, DockLayout.onDockPropertyChanged, isDockValid));
public static stretchLastChildProperty = new dependencyObservable.Property(
"stretchLastChild", "DockLayout", new proxy.PropertyMetadata(true, AffectsLayout));
public static getDock(element: view.View): string {
return validateArgs(element)._getValue(DockLayout.dockProperty);
}
public static setDock(element: view.View, value: string): void {
validateArgs(element)._setValue(DockLayout.dockProperty, value);
}
get stretchLastChild(): boolean {
return this._getValue(DockLayout.stretchLastChildProperty);
}
set stretchLastChild(value: boolean) {
this._setValue(DockLayout.stretchLastChildProperty, value);
}
protected onDockChanged(view: view.View, oldValue: number, newValue: number) {
//
}
}

View File

@@ -0,0 +1,69 @@
import definition = require("ui/layouts/dock-layout");
import dependencyObservable = require("ui/core/dependency-observable");
import view = require("ui/core/view");
import enums = require("ui/enums");
import proxy = require("ui/core/proxy");
import common = require("ui/layouts/dock-layout/dock-layout-common");
// merge the exports of the common file with the exports of this file
declare var exports;
require("utils/module-merge").merge(common, exports);
function setNativeDockProperty(data: dependencyObservable.PropertyChangeData) {
var uiView = data.object;
if (uiView instanceof view.View) {
var nativeView: android.view.View = uiView._nativeView;
var lp = <org.nativescript.widgets.CommonLayoutParams>nativeView.getLayoutParams();
if (!(lp instanceof org.nativescript.widgets.CommonLayoutParams)) {
lp = new org.nativescript.widgets.CommonLayoutParams();
}
switch (data.newValue) {
case enums.Dock.left:
lp.dock = org.nativescript.widgets.Dock.left;
break;
case enums.Dock.top:
lp.dock = org.nativescript.widgets.Dock.top;
break;
case enums.Dock.right:
lp.dock = org.nativescript.widgets.Dock.right;
break;
case enums.Dock.bottom:
lp.dock = org.nativescript.widgets.Dock.bottom;
break;
default:
throw new Error("Invalid dock value: " + data.newValue + " on element: " + uiView);
}
nativeView.setLayoutParams(lp);
}
}
(<proxy.PropertyMetadata>common.DockLayout.dockProperty.metadata).onSetNativeValue = setNativeDockProperty;
export class DockLayout extends common.DockLayout {
static setNativeStretchLastChildProperty(data: dependencyObservable.PropertyChangeData) {
var dockLayout = <DockLayout>data.object;
var nativeView = dockLayout._nativeView;
nativeView.setStretchLastChild(data.newValue);
}
private _layout: org.nativescript.widgets.DockLayout;
get android(): org.nativescript.widgets.DockLayout {
return this._layout;
}
get _nativeView(): org.nativescript.widgets.DockLayout {
return this._layout;
}
public _createUI() {
this._layout = new org.nativescript.widgets.DockLayout(this._context);
}
}
(<proxy.PropertyMetadata>common.DockLayout.stretchLastChildProperty.metadata).onSetNativeValue = DockLayout.setNativeStretchLastChildProperty;

View File

@@ -1,12 +1,12 @@
declare module "ui/layouts/dock-layout" {
import view = require("ui/core/view");
import layout = require("ui/layouts/layout");
import layout = require("ui/layouts/layout-base");
import dependencyObservable = require("ui/core/dependency-observable");
/**
* A Layout that arranges its children at its outer edges, and allows its last child to take up the remaining space.
*/
class DockLayout extends layout.Layout {
class DockLayout extends layout.LayoutBase {
/**
* Represents the observable property backing the dock property.

View File

@@ -1,53 +1,12 @@
import layouts = require("ui/layouts/layout");
import definition = require("ui/layouts/dock-layout");
import utils = require("utils/utils");
import dependencyObservable = require("ui/core/dependency-observable");
import utils = require("utils/utils");
import view = require("ui/core/view");
import enums = require("ui/enums");
import proxy = require("ui/core/proxy");
import common = require("ui/layouts/dock-layout/dock-layout-common");
function isDockValid(value: any): boolean {
return value === enums.Dock.left || value === enums.Dock.top || value === enums.Dock.right || value === enums.Dock.bottom;
}
export class DockLayout extends common.DockLayout {
function onDockPropertyChanged(data: dependencyObservable.PropertyChangeData) {
var uiView = data.object;
if (uiView instanceof view.View) {
var layout = (<view.View>uiView).parent;
if (layout instanceof DockLayout) {
layout.requestLayout();
}
}
}
export class DockLayout extends layouts.Layout implements definition.DockLayout {
public static dockProperty = new dependencyObservable.Property(
"dock", "DockLayout", new dependencyObservable.PropertyMetadata(enums.Dock.left, undefined, onDockPropertyChanged, isDockValid));
public static stretchLastChildProperty = new dependencyObservable.Property(
"stretchLastChild", "DockLayout", new proxy.PropertyMetadata(true, dependencyObservable.PropertyMetadataSettings.AffectsLayout));
public static getDock(element: view.View): string {
if (!element) {
throw new Error("element cannot be null or undefinied.");
}
return element._getValue(DockLayout.dockProperty);
}
public static setDock(element: view.View, value: string): void {
if (!element) {
throw new Error("element cannot be null or undefinied.");
}
element._setValue(DockLayout.dockProperty, value);
}
get stretchLastChild(): boolean {
return this._getValue(DockLayout.stretchLastChildProperty);
}
set stretchLastChild(value: boolean) {
this._setValue(DockLayout.stretchLastChildProperty, value);
protected onDockChanged(view: view.View, oldValue: number, newValue: number) {
this.requestLayout();
}
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {

View File

@@ -0,0 +1,370 @@
import layouts = require("ui/layouts/layout-base");
import definition = require("ui/layouts/grid-layout");
import utils = require("utils/utils");
import dependencyObservable = require("ui/core/dependency-observable");
import enums = require("ui/enums");
import view = require("ui/core/view");
import bindable = require("ui/core/bindable");
import types = require("utils/types");
import numberUtils = require("utils/number-utils");
import proxy = require("ui/core/proxy");
function validateArgs(element: view.View): view.View {
if (!element) {
throw new Error("element cannot be null or undefinied.");
}
return element;
}
export module GridUnitType {
export var auto: string = "auto";
export var pixel: string = "pixel";
export var star: string = "star";
}
export class ItemSpec extends bindable.Bindable implements definition.ItemSpec {
private _value: number;
private _unitType: string;
constructor() {
super();
if (arguments.length === 0) {
this._value = 1;
this._unitType = GridUnitType.star;
}
else if (arguments.length === 2) {
if (types.isNumber(arguments[0]) && types.isString(arguments[1])) {
if (arguments[0] < 0 || (arguments[1] !== GridUnitType.auto && arguments[1] !== GridUnitType.star && arguments[1] !== GridUnitType.pixel)) {
throw new Error("Invalid values.");
}
this._value = arguments[0];
this._unitType = arguments[1];
}
else {
throw new Error("Arguments must be number and string.");
}
}
else {
throw new Error("ItemSpec expects 0 or 2 arguments");
}
this.index = -1;
}
public owner: GridLayout;
public index: number;
public _actualLength: number = 0;
public get actualLength(): number {
return this._actualLength;
}
public set actualLength(value: number) {
throw new Error("actualLength is read-only property");
}
public static equals(value1: ItemSpec, value2: ItemSpec): boolean {
return (value1.gridUnitType === value2.gridUnitType) && (value1.value === value2.value) && (value1.owner === value2.owner) && (value1.index === value2.index);
}
get gridUnitType(): string {
return this._unitType;
}
get isAbsolute(): boolean {
return this._unitType === GridUnitType.pixel;
}
get isAuto(): boolean {
return this._unitType === GridUnitType.auto;
}
get isStar(): boolean {
return this._unitType === GridUnitType.star;
}
get value(): number {
return this._value;
}
}
export class GridLayout extends layouts.LayoutBase implements definition.GridLayout, view.ApplyXmlAttributes {
private _rows: Array<ItemSpec> = new Array<ItemSpec>();
private _cols: Array<ItemSpec> = new Array<ItemSpec>();
protected _singleRow: ItemSpec = new ItemSpec();
protected _singleColumn: ItemSpec = new ItemSpec();
public static columnProperty = new dependencyObservable.Property("Column", "GridLayout",
new proxy.PropertyMetadata(0, dependencyObservable.PropertyMetadataSettings.None, GridLayout.onColumnPropertyChanged, numberUtils.notNegative));
public static columnSpanProperty = new dependencyObservable.Property("ColumnSpan", "GridLayout",
new proxy.PropertyMetadata(1, dependencyObservable.PropertyMetadataSettings.None, GridLayout.onColumnSpanPropertyChanged, numberUtils.greaterThanZero));
public static rowProperty = new dependencyObservable.Property("Row", "GridLayout",
new proxy.PropertyMetadata(0, dependencyObservable.PropertyMetadataSettings.None, GridLayout.onRowPropertyChanged, numberUtils.notNegative));
public static rowSpanProperty = new dependencyObservable.Property("RowSpan", "GridLayout",
new proxy.PropertyMetadata(1, dependencyObservable.PropertyMetadataSettings.None, GridLayout.onRowSpanPropertyChanged, numberUtils.greaterThanZero));
public static getColumn(element: view.View): number {
return validateArgs(element)._getValue(GridLayout.columnProperty);
}
public static setColumn(element: view.View, value: number): void {
validateArgs(element)._setValue(GridLayout.columnProperty, value);
}
public static getColumnSpan(element: view.View): number {
return validateArgs(element)._getValue(GridLayout.columnSpanProperty);
}
public static setColumnSpan(element: view.View, value: number): void {
validateArgs(element)._setValue(GridLayout.columnSpanProperty, value);
}
public static getRow(element: view.View): number {
return validateArgs(element)._getValue(GridLayout.rowProperty);
}
public static setRow(element: view.View, value: number): void {
validateArgs(element)._setValue(GridLayout.rowProperty, value);
}
public static getRowSpan(element: view.View): number {
return validateArgs(element)._getValue(GridLayout.rowSpanProperty);
}
public static setRowSpan(element: view.View, value: number): void {
validateArgs(element)._setValue(GridLayout.rowSpanProperty, value);
}
constructor() {
super();
this._singleRow.index = 0
this._singleColumn.index = 0;
}
public addRow(itemSpec: ItemSpec) {
GridLayout.validateItemSpec(itemSpec);
itemSpec.owner = this;
this._rows.push(itemSpec);
this.onRowAdded(itemSpec);
}
public addColumn(itemSpec: ItemSpec) {
GridLayout.validateItemSpec(itemSpec);
itemSpec.owner = this;
this._cols.push(itemSpec);
this.onColumnAdded(itemSpec);
}
public removeRow(itemSpec: ItemSpec): void {
if (!itemSpec) {
throw new Error("Value is null.");
}
var index = this._rows.indexOf(itemSpec);
if (itemSpec.owner !== this || index < 0) {
throw new Error("Row is not child of this GridLayout");
}
itemSpec.index = -1;
this._rows.splice(index, 1);
this.onRowRemoved(itemSpec, index);
}
public removeColumn(itemSpec: ItemSpec): void {
if (!itemSpec) {
throw new Error("Value is null.");
}
var index = this._cols.indexOf(itemSpec);
if (itemSpec.owner !== this || index < 0) {
throw new Error("Column is not child of this GridLayout");
}
itemSpec.index = -1;
this._cols.splice(index, 1);
this.onColumnRemoved(itemSpec, index);
}
protected onRowChanged(element: view.View, oldValue: number, newValue: number) {
//
}
protected onRowSpanChanged(element: view.View, oldValue: number, newValue: number) {
//
}
protected onColumnChanged(element: view.View, oldValue: number, newValue: number) {
//
}
protected onColumnSpanChanged(element: view.View, oldValue: number, newValue: number) {
//
}
protected onRowAdded(itemSpec: ItemSpec) {
//
}
protected onColumnAdded(itemSpec: ItemSpec) {
//
}
protected onRowRemoved(itemSpec: ItemSpec, index: number) {
//
}
protected onColumnRemoved(itemSpec: ItemSpec, index: number) {
//
}
public getColumns(): Array<ItemSpec> {
return this._cols.slice();
}
public getRows(): Array<ItemSpec> {
return this._rows.slice();
}
protected getColumn(view: view.View): ItemSpec {
if (this._cols.length === 0) {
return this._singleColumn;
}
var columnIndex = Math.min(GridLayout.getColumn(view), this._cols.length - 1);
return this._cols[columnIndex];
}
protected getRow(view: view.View): ItemSpec {
if (this._rows.length === 0) {
return this._singleRow;
}
var columnIndex = Math.min(GridLayout.getRow(view), this._rows.length - 1);
return this._rows[columnIndex];
}
protected getColumnSpan(view: view.View, columnIndex: number): number {
if (this._cols.length === 0) {
return 1;
}
return Math.min(GridLayout.getColumnSpan(view), this._cols.length - columnIndex);
}
protected getRowSpan(view: view.View, rowIndex: number): number {
if (this._rows.length === 0) {
return 1;
}
return Math.min(GridLayout.getRowSpan(view), this._rows.length - rowIndex);
}
protected invalidate(): void {
//
}
applyXmlAttribute(attributeName: string, attributeValue: any): boolean {
if (attributeName === "columns") {
this.setColumns(attributeValue);
return true;
}
else if (attributeName === "rows") {
this.setRows(attributeValue);
return true;
}
return false;
}
private static parseItemSpecs(value: string): Array<ItemSpec> {
var result = new Array<ItemSpec>();
var arr = value.split(",");
for (var i = 0; i < arr.length; i++) {
result.push(GridLayout.convertGridLength(arr[i].trim()));
}
return result;
}
private static convertGridLength(value: string): ItemSpec {
if (value === "auto") {
return <ItemSpec>new definition.ItemSpec(1, definition.GridUnitType.auto);
}
else if (value.indexOf("*") !== -1) {
var starCount = parseInt(value.replace("*", "") || "1");
return <ItemSpec>new definition.ItemSpec(starCount, definition.GridUnitType.star);
}
else if (!isNaN(parseInt(value))) {
return <ItemSpec>new definition.ItemSpec(parseInt(value), definition.GridUnitType.pixel);
}
else {
throw new Error("Cannot parse item spec from string: " + value);
}
}
private static onRowPropertyChanged(data: dependencyObservable.PropertyChangeData): void {
var element = GridLayout.getView(data.object);
var grid = element.parent;
if (grid instanceof GridLayout) {
grid.onRowChanged(element, data.oldValue, data.newValue);
}
}
private static onColumnPropertyChanged(data: dependencyObservable.PropertyChangeData): void {
var element = GridLayout.getView(data.object);
var grid = element.parent;
if (grid instanceof GridLayout) {
grid.onColumnChanged(element, data.oldValue, data.newValue);
}
}
private static onRowSpanPropertyChanged(data: dependencyObservable.PropertyChangeData): void {
var element = GridLayout.getView(data.object);
var grid = element.parent;
if (grid instanceof GridLayout) {
grid.onRowSpanChanged(element, data.oldValue, data.newValue);
}
}
private static onColumnSpanPropertyChanged(data: dependencyObservable.PropertyChangeData): void {
var element = GridLayout.getView(data.object);
var grid = element.parent;
if (grid instanceof GridLayout) {
grid.onColumnSpanChanged(element, data.oldValue, data.newValue);
}
}
private static validateItemSpec(itemSpec: ItemSpec): void {
if (!itemSpec) {
throw new Error("Value cannot be undefined.");
}
if (itemSpec.owner) {
throw new Error("itemSpec is already added to GridLayout.");
}
}
private static getView(object: Object): view.View {
if (object instanceof view.View) {
return object;
}
throw new Error("Element is not View or its descendant.");
}
private setColumns(value: string) {
this._cols = GridLayout.parseItemSpecs(value);
this.invalidate();
}
private setRows(value: string) {
this._rows = GridLayout.parseItemSpecs(value);
this.invalidate();
}
}

View File

@@ -0,0 +1,111 @@
import definition = require("ui/layouts/grid-layout");
import utils = require("utils/utils");
import dependencyObservable = require("ui/core/dependency-observable");
import enums = require("ui/enums");
import view = require("ui/core/view");
import bindable = require("ui/core/bindable");
import types = require("utils/types");
import proxy = require("ui/core/proxy");
import common = require("ui/layouts/grid-layout/grid-layout-common");
// merge the exports of the common file with the exports of this file
declare var exports;
require("utils/module-merge").merge(common, exports);
function setNativeProperty(data: dependencyObservable.PropertyChangeData, setter: (lp: org.nativescript.widgets.CommonLayoutParams) => void) {
var uiView = data.object;
if (uiView instanceof view.View) {
var nativeView: android.view.View = uiView._nativeView;
var lp = <org.nativescript.widgets.CommonLayoutParams>nativeView.getLayoutParams();
if (!(lp instanceof org.nativescript.widgets.CommonLayoutParams)) {
lp = new org.nativescript.widgets.CommonLayoutParams();
}
setter(lp);
nativeView.setLayoutParams(lp);
}
}
function setNativeRowProperty(data: dependencyObservable.PropertyChangeData) {
setNativeProperty(data, (lp) => { lp.row = data.newValue; });
}
function setNativeRowSpanProperty(data: dependencyObservable.PropertyChangeData) {
setNativeProperty(data, (lp) => { lp.rowSpan = data.newValue; });
}
function setNativeColumnProperty(data: dependencyObservable.PropertyChangeData) {
setNativeProperty(data, (lp) => { lp.column = data.newValue; });
}
function setNativeColumnSpanProperty(data: dependencyObservable.PropertyChangeData) {
setNativeProperty(data, (lp) => { lp.columnSpan = data.newValue; });
}
(<proxy.PropertyMetadata>common.GridLayout.rowProperty.metadata).onSetNativeValue = setNativeRowProperty;
(<proxy.PropertyMetadata>common.GridLayout.rowSpanProperty.metadata).onSetNativeValue = setNativeRowSpanProperty;
(<proxy.PropertyMetadata>common.GridLayout.columnProperty.metadata).onSetNativeValue = setNativeColumnProperty;
(<proxy.PropertyMetadata>common.GridLayout.columnSpanProperty.metadata).onSetNativeValue = setNativeColumnSpanProperty;
function createNativeSpec(itemSpec: common.ItemSpec): org.nativescript.widgets.ItemSpec {
switch (itemSpec.gridUnitType) {
case common.GridUnitType.auto:
return new org.nativescript.widgets.ItemSpec(itemSpec.value, org.nativescript.widgets.GridUnitType.auto);
case common.GridUnitType.star:
return new org.nativescript.widgets.ItemSpec(itemSpec.value, org.nativescript.widgets.GridUnitType.star);
case common.GridUnitType.pixel:
return new org.nativescript.widgets.ItemSpec(itemSpec.value * utils.layout.getDisplayDensity(), org.nativescript.widgets.GridUnitType.pixel);
default:
throw new Error("Invalid gridUnitType: " + itemSpec.gridUnitType);
}
}
export class GridLayout extends common.GridLayout {
private _layout: org.nativescript.widgets.GridLayout;
get android(): org.nativescript.widgets.GridLayout {
return this._layout;
}
get _nativeView(): org.nativescript.widgets.GridLayout {
return this._layout;
}
public _createUI() {
this._layout = new org.nativescript.widgets.GridLayout(this._context);
// Update native GridLayout
this.getRows().forEach((itemSpec, index, rows) => { this.onRowAdded(itemSpec); }, this);
this.getColumns().forEach((itemSpec, index, rows) => { this.onColumnAdded(itemSpec); }, this);
}
protected onRowAdded(itemSpec: common.ItemSpec) {
if (this._layout) {
this._layout.addRow(createNativeSpec(itemSpec));
}
}
protected onColumnAdded(itemSpec: common.ItemSpec) {
if (this._layout) {
this._layout.addColumn(createNativeSpec(itemSpec));
}
}
protected onRowRemoved(itemSpec: common.ItemSpec, index: number) {
if (this._layout) {
this._layout.removeRowAt(index);
}
}
protected onColumnRemoved(itemSpec: common.ItemSpec, index: number) {
if (this._layout) {
this._layout.removeColumnAt(index);
}
}
}

View File

@@ -1,5 +1,5 @@
declare module "ui/layouts/grid-layout" {
import layout = require("ui/layouts/layout");
import layout = require("ui/layouts/layout-base");
import view = require("ui/core/view");
/**
@@ -68,7 +68,7 @@
/**
* Defines a rectangular layout area that consists of columns and rows.
*/
export class GridLayout extends layout.Layout {
export class GridLayout extends layout.LayoutBase {
///**
// * Initializes a new instance of GridLayout.

View File

@@ -1,295 +1,54 @@
import layouts = require("ui/layouts/layout");
import definition = require("ui/layouts/grid-layout");
import utils = require("utils/utils");
import dependencyObservable = require("ui/core/dependency-observable");
import utils = require("utils/utils");
import enums = require("ui/enums");
import view = require("ui/core/view");
import bindable = require("ui/core/bindable");
import types = require("utils/types");
import numberUtils = require("utils/number-utils");
import common = require("ui/layouts/grid-layout/grid-layout-common");
export module GridUnitType {
export var auto: string = "auto";
export var pixel: string = "pixel";
export var star: string = "star";
}
// merge the exports of the common file with the exports of this file
declare var exports;
require("utils/module-merge").merge(common, exports);
export class ItemSpec extends bindable.Bindable implements definition.ItemSpec {
private _value: number;
private _unitType: string;
constructor() {
super();
if (arguments.length === 0) {
this._value = 1;
this._unitType = GridUnitType.star;
}
else if (arguments.length === 2) {
if (types.isNumber(arguments[0]) && types.isString(arguments[1])) {
if (arguments[0] < 0 || (arguments[1] !== GridUnitType.auto && arguments[1] !== GridUnitType.star && arguments[1] !== GridUnitType.pixel)) {
throw new Error("Invalid values.");
}
this._value = arguments[0];
this._unitType = arguments[1];
}
else {
throw new Error("Arguments must be number and string.");
}
}
else {
throw new Error("ItemSpec expects 0 or 2 arguments");
}
this.index = -1;
}
public owner: GridLayout;
public index: number;
public _actualLength: number = 0;
public get actualLength(): number {
return this._actualLength;
}
public set actualLength(value: number) {
throw new Error("actualLength is read-only property");
}
public static equals(value1: ItemSpec, value2: ItemSpec): boolean {
return (value1.gridUnitType === value2.gridUnitType) && (value1.value === value2.value) && (value1.owner === value2.owner) && (value1.index === value2.index);
}
get gridUnitType(): string {
return this._unitType;
}
get isAbsolute(): boolean {
return this._unitType === GridUnitType.pixel;
}
get isAuto(): boolean {
return this._unitType === GridUnitType.auto;
}
get isStar(): boolean {
return this._unitType === GridUnitType.star;
}
get value(): number {
return this._value;
}
}
export class GridLayout extends layouts.Layout implements definition.GridLayout, view.ApplyXmlAttributes {
private _rows: Array<ItemSpec> = new Array<ItemSpec>();
private _cols: Array<ItemSpec> = new Array<ItemSpec>();
private _singleRow: ItemSpec = new ItemSpec();
private _singleColumn: ItemSpec = new ItemSpec();
export class GridLayout extends common.GridLayout {
private _isValid: boolean = false;
private helper: MeasureHelper;
public static columnProperty = new dependencyObservable.Property("Column", "GridLayout",
new dependencyObservable.PropertyMetadata(0, dependencyObservable.PropertyMetadataSettings.None, GridLayout.attachedPropertyChanged, numberUtils.notNegative));
public static columnSpanProperty = new dependencyObservable.Property("ColumnSpan", "GridLayout",
new dependencyObservable.PropertyMetadata(1, dependencyObservable.PropertyMetadataSettings.None, GridLayout.attachedPropertyChanged, numberUtils.greaterThanZero));
public static rowProperty = new dependencyObservable.Property("Row", "GridLayout",
new dependencyObservable.PropertyMetadata(0, dependencyObservable.PropertyMetadataSettings.None, GridLayout.attachedPropertyChanged, numberUtils.notNegative));
public static rowSpanProperty = new dependencyObservable.Property("RowSpan", "GridLayout",
new dependencyObservable.PropertyMetadata(1, dependencyObservable.PropertyMetadataSettings.None, GridLayout.attachedPropertyChanged, numberUtils.greaterThanZero));
public static getColumn(element: view.View): number {
if (!element) {
throw new Error("element cannot be null or undefinied.");
protected onRowAdded(itemSpec: common.ItemSpec) {
this.invalidate();
}
return element._getValue(GridLayout.columnProperty);
}
public static setColumn(element: view.View, value: number): void {
if (!element) {
throw new Error("element cannot be null or undefinied.");
}
element._setValue(GridLayout.columnProperty, value);
}
public static getColumnSpan(element: view.View): number {
if (!element) {
throw new Error("element cannot be null or undefinied.");
}
return element._getValue(GridLayout.columnSpanProperty);
}
public static setColumnSpan(element: view.View, value: number): void {
if (!element) {
throw new Error("element cannot be null or undefinied.");
}
element._setValue(GridLayout.columnSpanProperty, value);
}
public static getRow(element: view.View): number {
if (!element) {
throw new Error("element cannot be null or undefinied.");
}
return <number>element._getValue(GridLayout.rowProperty);
}
public static setRow(element: view.View, value: number): void {
if (!element) {
throw new Error("element cannot be null or undefinied.");
}
element._setValue(GridLayout.rowProperty, value);
}
public static getRowSpan(element: view.View): number {
if (!element) {
throw new Error("element cannot be null or undefinied.");
}
return element._getValue(GridLayout.rowSpanProperty);
}
public static setRowSpan(element: view.View, value: number): void {
if (!element) {
throw new Error("element cannot be null or undefinied.");
}
element._setValue(GridLayout.rowSpanProperty, value);
}
private static attachedPropertyChanged(data: dependencyObservable.PropertyChangeData): void {
if (data.object instanceof view.View) {
var element = <view.View>data.object;
if (!element) {
throw new Error("Element is not View.");
}
var grid = element.parent;
if (grid instanceof GridLayout) {
grid.invalidate();
}
}
}
private static validateItemSpec(itemSpec: ItemSpec): void {
if (!itemSpec) {
throw new Error("Value cannot be undefined.");
}
if (itemSpec.owner) {
throw new Error("itemSpec is already added to GridLayout.");
}
}
constructor() {
super();
this._singleRow.index = 0
this._singleColumn.index = 0;
}
public addRow(itemSpec: ItemSpec) {
GridLayout.validateItemSpec(itemSpec);
itemSpec.owner = this;
this._rows.push(itemSpec);
protected onColumnAdded(itemSpec: common.ItemSpec) {
this.invalidate();
}
public addColumn(itemSpec: ItemSpec) {
GridLayout.validateItemSpec(itemSpec);
itemSpec.owner = this;
this._cols.push(itemSpec);
protected onRowRemoved(itemSpec: common.ItemSpec, index: number) {
this.invalidate();
}
public removeColumn(itemSpec: ItemSpec): void {
if (!itemSpec) {
throw new Error("Value is null.");
}
var index = this._cols.indexOf(itemSpec);
if (itemSpec.owner !== this || index < 0) {
throw new Error("Column is not child of this GridLayout");
}
itemSpec.index = -1;
this._cols.splice(index, 1);
protected onColumnRemoved(itemSpec: common.ItemSpec, index: number) {
this.invalidate();
}
public removeRow(itemSpec: ItemSpec): void {
if (!itemSpec) {
throw new Error("Value is null.");
}
var index = this._rows.indexOf(itemSpec);
if (itemSpec.owner !== this || index < 0) {
throw new Error("Row is not child of this GridLayout");
}
itemSpec.index = -1;
this._rows.splice(index, 1);
protected onRowChanged(element: view.View, oldValue: number, newValue: number) {
this.invalidate();
}
public getColumns(): Array<ItemSpec> {
return this._cols.slice();
}
public getRows(): Array<ItemSpec> {
return this._rows.slice();
}
private setColumns(value: string) {
this._cols = GridLayout.parseItemSpecs(value);
protected onRowSpanChanged(element: view.View, oldValue: number, newValue: number) {
this.invalidate();
}
private setRows(value: string) {
this._rows = GridLayout.parseItemSpecs(value);
protected onColumnChanged(element: view.View, oldValue: number, newValue: number) {
this.invalidate();
}
public invalidate(): void {
protected onColumnSpanChanged(element: view.View, oldValue: number, newValue: number) {
this.invalidate();
}
protected invalidate(): void {
this._isValid = false;
this.requestLayout();
}
private getColumn(view: view.View): ItemSpec {
if (this._cols.length === 0) {
return this._singleColumn;
}
var columnIndex = Math.min(GridLayout.getColumn(view), this._cols.length - 1);
return this._cols[columnIndex];
}
private getRow(view: view.View): ItemSpec {
if (this._rows.length === 0) {
return this._singleRow;
}
var columnIndex = Math.min(GridLayout.getRow(view), this._rows.length - 1);
return this._rows[columnIndex];
}
private getColumnSpan(view: view.View, columnIndex: number): number {
if (this._cols.length === 0) {
return 1;
}
return Math.min(GridLayout.getColumnSpan(view), this._cols.length - columnIndex);
}
private getRowSpan(view: view.View, rowIndex: number): number {
if (this._rows.length === 0) {
return 1;
}
return Math.min(GridLayout.getRowSpan(view), this._rows.length - rowIndex);
}
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -306,17 +65,20 @@ export class GridLayout extends layouts.Layout implements definition.GridLayout,
var infinityWidth = widthMode === utils.layout.UNSPECIFIED;
var infinityHeight = heightMode === utils.layout.UNSPECIFIED;
var column: ItemSpec;
var column: common.ItemSpec;
var columnGroup: ColumnGroup;
var row: ItemSpec;
var row: common.ItemSpec;
var rowGroup: RowGroup;
var rows = this.getRows();
var cols = this.getColumns();
if (!this._isValid) {
this._rows.forEach((value: ItemSpec, index: number, array: ItemSpec[]) => {
rows.forEach((value: common.ItemSpec, index: number, array: common.ItemSpec[]) => {
value.index = index;
});
this._cols.forEach((value: ItemSpec, index: number, array: ItemSpec[]) => {
cols.forEach((value: common.ItemSpec, index: number, array: common.ItemSpec[]) => {
value.index = index;
});
@@ -327,8 +89,8 @@ export class GridLayout extends layouts.Layout implements definition.GridLayout,
this.helper.infinityWidth = infinityWidth;
this.helper.infinityHeight = infinityHeight;
for (i = 0; i < this._cols.length; i++) {
column = this._cols[i];
for (i = 0; i < cols.length; i++) {
column = cols[i];
columnGroup = new ColumnGroup(column, this.helper);
this.helper.columns.push(columnGroup);
if (column.isAbsolute) {
@@ -336,8 +98,8 @@ export class GridLayout extends layouts.Layout implements definition.GridLayout,
}
}
for (i = 0; i < this._rows.length; i++) {
row = this._rows[i];
for (i = 0; i < rows.length; i++) {
row = rows[i];
rowGroup = new RowGroup(row, this.helper);
this.helper.rows.push(rowGroup);
if (row.isAbsolute) {
@@ -345,11 +107,11 @@ export class GridLayout extends layouts.Layout implements definition.GridLayout,
}
}
if (this._rows.length === 0) {
if (rows.length === 0) {
this.helper.rows.push(new RowGroup(this._singleRow, this.helper));
}
if (this._cols.length === 0) {
if (cols.length === 0) {
this.helper.columns.push(new ColumnGroup(this._singleColumn, this.helper));
}
}
@@ -445,44 +207,6 @@ export class GridLayout extends layouts.Layout implements definition.GridLayout,
}
}
}
_applyXmlAttribute(attributeName: string, attributeValue: any): boolean {
if (attributeName === "columns") {
this.setColumns(attributeValue);
return true;
}
else if (attributeName === "rows") {
this.setRows(attributeValue);
return true;
}
return super._applyXmlAttribute(attributeName, attributeValue);
}
private static parseItemSpecs(value: string): Array<ItemSpec> {
var result = new Array<ItemSpec>();
var arr = value.split(",");
for (var i = 0; i < arr.length; i++) {
result.push(GridLayout.convertGridLength(arr[i].trim()));
}
return result;
}
private static convertGridLength(value: string): ItemSpec {
if (value === "auto") {
return <ItemSpec>new definition.ItemSpec(1, definition.GridUnitType.auto);
} else if (value.indexOf("*") !== -1) {
var starCount = parseInt(value.replace("*", "") || "1");
return <ItemSpec>new definition.ItemSpec(starCount, definition.GridUnitType.star);
} else if (!isNaN(parseInt(value))) {
return <ItemSpec>new definition.ItemSpec(parseInt(value), definition.GridUnitType.pixel);
}
else {
throw new Error("Cannot parse item spec from string: " + value);
}
}
}
class MeasureSpecs {
@@ -503,8 +227,8 @@ class MeasureSpecs {
constructor(
public child: view.View,
public column: ItemSpec,
public row: ItemSpec,
public column: common.ItemSpec,
public row: common.ItemSpec,
columnSpan?: number,
rowSpan?: number) {
// cannot have zero colSpan.
@@ -546,14 +270,14 @@ class MeasureSpecs {
class ColumnGroup {
width: number = 0;
measuredCount = 0;
column: ItemSpec;
column: common.ItemSpec;
children: Array<MeasureSpecs> = new Array<MeasureSpecs>();
owner: MeasureHelper;
public measureToFix: number = 0;
public currentMeasureToFixCount: number = 0;
constructor(column: ItemSpec, owner: MeasureHelper) {
constructor(column: common.ItemSpec, owner: MeasureHelper) {
this.owner = owner;
this.column = column;
}
@@ -587,14 +311,14 @@ class ColumnGroup {
class RowGroup {
height: number = 0;
measuredCount = 0;
row: ItemSpec;
row: common.ItemSpec;
children: Array<MeasureSpecs> = new Array<MeasureSpecs>();
owner: MeasureHelper;
public measureToFix: number = 0;
public currentMeasureToFixCount: number = 0;
constructor(row: ItemSpec, owner: MeasureHelper) {
constructor(row: common.ItemSpec, owner: MeasureHelper) {
this.row = row;
this.owner = owner;
}

60
ui/layouts/layout-base.d.ts vendored Normal file
View File

@@ -0,0 +1,60 @@
declare module "ui/layouts/layout-base" {
import view = require("ui/core/view");
import dependencyObservable = require("ui/core/dependency-observable");
/**
* Base class for all views that supports children positioning.
*/
export class LayoutBase extends view.CustomLayoutView {
public static clipToBoundsProperty: dependencyObservable.Property;
/**
* Returns the number of children in this Layout.
*/
getChildrenCount(): number;
/**
* Returns the view at the specified position.
* @param index The position at which to get the child from.
*/
getChildAt(index: number): view.View;
/**
* Adds the view to children array.
* @param view The view to be added to the end of the children array.
*/
addChild(view: view.View);
/**
* Removes the specified view from the children array.
* @param view The view to remove from the children array.
*/
removeChild(view: view.View);
/**
* Gets or sets padding style property.
*/
padding: string;
/**
* Specify the bottom padding of this layout.
*/
paddingBottom: number;
/**
* Specify the left padding of this layout.
*/
paddingLeft: number;
/**
* Specify the right padding of this layout.
*/
paddingRight: number;
/**
* Specify the top padding of this layout.
*/
paddingTop: number;
}
}

View File

@@ -1,31 +1,12 @@
import definition = require("ui/layouts/layout");
import definition = require("ui/layouts/layout-base");
import view = require("ui/core/view");
import dependencyObservable = require("ui/core/dependency-observable");
import proxy = require("ui/core/proxy");
function onClipToBoundsPropertyChanged(data: dependencyObservable.PropertyChangeData) {
var nativeView = (<Layout>data.object)._nativeView;
if (!nativeView) {
return;
}
var value = <boolean>data.newValue;
export class LayoutBase extends view.CustomLayoutView implements definition.LayoutBase, view.AddChildFromBuilder {
if (nativeView instanceof UIView) {
(<UIView>nativeView).clipsToBounds = value;
}
else if (nativeView instanceof android.view.ViewGroup) {
(<android.view.ViewGroup>nativeView).setClipChildren(value);
}
}
var clipToBoundsProperty = new dependencyObservable.Property(
"clipToBounds",
"Layout",
new proxy.PropertyMetadata(undefined, dependencyObservable.PropertyMetadataSettings.None, onClipToBoundsPropertyChanged)
);
export class Layout extends view.CustomLayoutView implements definition.Layout, view.AddChildFromBuilder {
public static clipToBoundsProperty = clipToBoundsProperty;
public static clipToBoundsProperty = new dependencyObservable.Property("clipToBounds", "LayoutBase",
new proxy.PropertyMetadata(true, dependencyObservable.PropertyMetadataSettings.None, LayoutBase.onClipToBoundsPropertyChanged));
private _subViews: Array<view.View> = new Array<view.View>();
@@ -88,6 +69,13 @@ export class Layout extends view.CustomLayoutView implements definition.Layout,
}
}
get padding(): string {
return this.style.padding;
}
set padding(value: string) {
this.style.padding = value;
}
public get paddingTop(): number {
return this.style.paddingTop;
}
@@ -116,10 +104,12 @@ export class Layout extends view.CustomLayoutView implements definition.Layout,
this.style.paddingLeft = value;
}
get clipToBounds(): boolean {
return this._getValue(Layout.clipToBoundsProperty);
protected onClipToBoundsChanged(oldValue: boolean, newValue: boolean) {
//
}
private static onClipToBoundsPropertyChanged(data: dependencyObservable.PropertyChangeData): void {
var layout = <LayoutBase>data.object;
layout.onClipToBoundsChanged(data.oldValue, data.newValue);
}
set clipToBounds(value: boolean) {
this._setValue(Layout.clipToBoundsProperty, value);
}
}
}

View File

@@ -0,0 +1,72 @@
import definition = require("ui/layouts/layout");
import view = require("ui/core/view");
import layoutBase = require("ui/layouts/layout-base");
import trace = require("trace");
import utils = require("utils/utils");
import proxy = require("ui/core/proxy");
var OWNER = "_owner";
export class Layout extends layoutBase.LayoutBase implements definition.Layout {
private _viewGroup: android.view.ViewGroup;
get android(): android.view.ViewGroup {
return this._viewGroup;
}
get _nativeView(): android.view.ViewGroup {
return this._viewGroup;
}
public _createUI() {
this._viewGroup = new view.NativeViewGroup(this._context);
this._viewGroup[OWNER] = this;
}
public _onDetached(force?: boolean) {
delete this._viewGroup[OWNER];
super._onDetached(force);
}
public measure(widthMeasureSpec: number, heightMeasureSpec: number): void {
this._setCurrentMeasureSpecs(widthMeasureSpec, heightMeasureSpec);
var view = this._nativeView;
if (view) {
var width = utils.layout.getMeasureSpecSize(widthMeasureSpec);
var widthMode = utils.layout.getMeasureSpecMode(widthMeasureSpec);
var height = utils.layout.getMeasureSpecSize(heightMeasureSpec);
var heightMode = utils.layout.getMeasureSpecMode(heightMeasureSpec);
trace.write(this + " :measure: " + utils.layout.getMode(widthMode) + " " + width + ", " + utils.layout.getMode(heightMode) + " " + height, trace.categories.Layout);
view.measure(widthMeasureSpec, heightMeasureSpec);
}
}
public layout(left: number, top: number, right: number, bottom: number): void {
this._setCurrentLayoutBounds(left, top, right, bottom);
var view = this._nativeView;
if (view) {
this.layoutNativeView(left, top, right, bottom);
trace.write(this + " :layout: " + left + ", " + top + ", " + (right - left) + ", " + (bottom - top), trace.categories.Layout);
}
}
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
// Don't call super because it will trigger measure again.
var width = utils.layout.getMeasureSpecSize(widthMeasureSpec);
var widthMode = utils.layout.getMeasureSpecMode(widthMeasureSpec);
var height = utils.layout.getMeasureSpecSize(heightMeasureSpec);
var heightMode = utils.layout.getMeasureSpecMode(heightMeasureSpec);
trace.write(this + " :onMeasure: " + utils.layout.getMode(widthMode) + " " + width + ", " + utils.layout.getMode(heightMode) + " " + height, trace.categories.Layout);
}
public onLayout(left: number, top: number, right: number, bottom: number): void {
// Don't call super because it will trigger layout again.
trace.write(this + " :onLayout: " + left + ", " + top + ", " + (right - left) + ", " + (bottom - top), trace.categories.Layout);
}
}

View File

@@ -1,65 +1,11 @@
declare module "ui/layouts/layout" {
import view = require("ui/core/view");
import layoutBase = require("ui/layouts/layout-base");
/**
* Base class for all views that supports children positioning.
* Base class for all views that supports children positioning in cross platform manner.
*/
export class Layout extends view.View {
/**
* Returns the number of children in this Layout.
*/
getChildrenCount(): number;
/**
* Returns the view at the specified position.
* @param index The position at which to get the child from.
*/
getChildAt(index: number): view.View;
/**
* Returns the position of the child view
* @param child The child view that we are looking for.
*/
getChildIndex(child: view.View): number;
/**
* Adds the view to children array.
* @param view The view to be added to the end of the children array.
*/
addChild(view: view.View);
/**
* Inserts the view to children array at the specified index.
* @param atIndex The insertion index.
* @param view The view to be added to the end of the children array.
*/
insertChild(atIndex: number, child: view.View);
/**
* Removes the specified view from the children array.
* @param view The view to remove from the children array.
*/
removeChild(view: view.View);
/**
* Specify the bottom padding of this layout.
*/
paddingBottom: number;
/**
* Specify the left padding of this layout.
*/
paddingLeft: number;
/**
* Specify the right padding of this layout.
*/
paddingRight: number;
/**
* Specify the top padding of this layout.
*/
paddingTop: number;
export class Layout extends layoutBase.LayoutBase {
//
}
}
}

41
ui/layouts/layout.ios.ts Normal file
View File

@@ -0,0 +1,41 @@
import definition = require("ui/layouts/layout");
import layoutBase = require("ui/layouts/layout-base");
import trace = require("trace");
import utils = require("utils/utils");
export class Layout extends layoutBase.LayoutBase implements definition.Layout {
private _view: UIView;
constructor() {
super();
this._view = new UIView();
this._view.autoresizesSubviews = false;
}
get ios(): UIView {
return this._view;
}
get _nativeView(): UIView {
return this._view;
}
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
// Don't call super because it will measure the native element.
var width = utils.layout.getMeasureSpecSize(widthMeasureSpec);
var widthMode = utils.layout.getMeasureSpecMode(widthMeasureSpec);
var height = utils.layout.getMeasureSpecSize(heightMeasureSpec);
var heightMode = utils.layout.getMeasureSpecMode(heightMeasureSpec);
trace.write(this + " :onMeasure: " + utils.layout.getMode(widthMode) + " " + width + ", " + utils.layout.getMode(heightMode) + " " + height, trace.categories.Layout);
}
protected onClipToBoundsChanged(oldValue: boolean, newValue: boolean): void {
if (this._nativeView) {
this._nativeView.clipsToBounds = newValue;
}
}
}

View File

@@ -0,0 +1,25 @@
import layouts = require("ui/layouts/layout-base");
import definition = require("ui/layouts/stack-layout");
import dependencyObservable = require("ui/core/dependency-observable");
import enums = require("ui/enums");
import proxy = require("ui/core/proxy");
// on Android we explicitly set propertySettings to None because android will invalidate its layout (skip unnecessary native call).
var AffectsLayout = global.android ? dependencyObservable.PropertyMetadataSettings.None : dependencyObservable.PropertyMetadataSettings.AffectsLayout;
function validateOrientation(value: any): boolean {
return value === enums.Orientation.vertical || value === enums.Orientation.horizontal;
}
export class StackLayout extends layouts.LayoutBase implements definition.StackLayout {
public static orientationProperty = new dependencyObservable.Property("orientation","StackLayout",
new proxy.PropertyMetadata(enums.Orientation.vertical, AffectsLayout, undefined, validateOrientation));
get orientation(): string {
return this._getValue(StackLayout.orientationProperty);
}
set orientation(value: string) {
this._setValue(StackLayout.orientationProperty, value);
}
}

View File

@@ -0,0 +1,38 @@
import dependencyObservable = require("ui/core/dependency-observable");
import proxy = require("ui/core/proxy");
import common = require("ui/layouts/stack-layout/stack-layout-common");
import enums = require("ui/enums");
// merge the exports of the common file with the exports of this file
declare var exports;
require("utils/module-merge").merge(common, exports);
export class StackLayout extends common.StackLayout {
static setNativeOrientationProperty(data: dependencyObservable.PropertyChangeData): void {
var stackLayout = <StackLayout>data.object;
var nativeView = stackLayout._nativeView;
if (data.newValue === enums.Orientation.vertical) {
nativeView.setOrientation(org.nativescript.widgets.Orientation.vertical);
}
else {
nativeView.setOrientation(org.nativescript.widgets.Orientation.horzontal);
}
}
private _layout: org.nativescript.widgets.StackLayout;
get android(): org.nativescript.widgets.StackLayout {
return this._layout;
}
get _nativeView(): org.nativescript.widgets.StackLayout {
return this._layout;
}
public _createUI() {
this._layout = new org.nativescript.widgets.StackLayout(this._context);
}
}
(<proxy.PropertyMetadata>common.StackLayout.orientationProperty.metadata).onSetNativeValue = StackLayout.setNativeOrientationProperty;

View File

@@ -1,11 +1,11 @@
declare module "ui/layouts/stack-layout" {
import layout = require("ui/layouts/layout");
import layout = require("ui/layouts/layout-base");
import dependencyObservable = require("ui/core/dependency-observable");
/**
* A Layout that arranges its children horizontally or vertically. The direction can be set by orientation property.
*/
class StackLayout extends layout.Layout {
class StackLayout extends layout.LayoutBase {
/**
* Represents the observable property backing the orientation property of each StackLayout instance.

View File

@@ -1,35 +1,16 @@
import layouts = require("ui/layouts/layout");
import definition = require("ui/layouts/stack-layout");
import utils = require("utils/utils");
import dependencyObservable = require("ui/core/dependency-observable");
import utils = require("utils/utils");
import enums = require("ui/enums");
import proxy = require("ui/core/proxy");
import view = require("ui/core/view");
import common = require("ui/layouts/stack-layout/stack-layout-common");
function validateOrientation(value: any): boolean {
return value === enums.Orientation.vertical || value === enums.Orientation.horizontal;
}
// merge the exports of the common file with the exports of this file
declare var exports;
require("utils/module-merge").merge(common, exports);
export var orientationProperty = new dependencyObservable.Property(
"orientation",
"StackLayout",
new proxy.PropertyMetadata(enums.Orientation.vertical,
dependencyObservable.PropertyMetadataSettings.AffectsLayout,
undefined,
validateOrientation)
);
export class StackLayout extends layouts.Layout implements definition.StackLayout {
export class StackLayout extends common.StackLayout {
private _totalLength = 0;
get orientation(): string {
return this._getValue(orientationProperty);
}
set orientation(value: string) {
this._setValue(orientationProperty, value);
}
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
var density = utils.layout.getDisplayDensity();

View File

@@ -0,0 +1,49 @@
import layouts = require("ui/layouts/layout-base");
import definition = require("ui/layouts/wrap-layout");
import dependencyObservable = require("ui/core/dependency-observable");
import enums = require("ui/enums");
import proxy = require("ui/core/proxy");
// on Android we explicitly set propertySettings to None because android will invalidate its layout (so we skip unnecessary native call).
var AffectsLayout = global.android ? dependencyObservable.PropertyMetadataSettings.None : dependencyObservable.PropertyMetadataSettings.AffectsLayout;
function isWidthHeightValid(value: any): boolean {
return (value >= 0.0 && value !== Number.POSITIVE_INFINITY);
}
function isValidOrientation(value: any): boolean {
return value === enums.Orientation.vertical || value === enums.Orientation.horizontal;
}
export class WrapLayout extends layouts.LayoutBase implements definition.WrapLayout {
public static orientationProperty = new dependencyObservable.Property("orientation", "WrapLayout",
new proxy.PropertyMetadata(enums.Orientation.horizontal, AffectsLayout, undefined, isValidOrientation));
public static itemWidthProperty = new dependencyObservable.Property("itemWidth", "WrapLayout",
new proxy.PropertyMetadata(0, AffectsLayout, undefined, isWidthHeightValid));
public static itemHeightProperty = new dependencyObservable.Property("itemHeight", "WrapLayout",
new proxy.PropertyMetadata(0, AffectsLayout, undefined, isWidthHeightValid));
get orientation(): string {
return this._getValue(WrapLayout.orientationProperty);
}
set orientation(value: string) {
this._setValue(WrapLayout.orientationProperty, value);
}
get itemWidth(): number {
return this._getValue(WrapLayout.itemWidthProperty);
}
set itemWidth(value: number) {
this._setValue(WrapLayout.itemWidthProperty, value);
}
get itemHeight(): number {
return this._getValue(WrapLayout.itemHeightProperty);
}
set itemHeight(value: number) {
this._setValue(WrapLayout.itemHeightProperty, value);
}
}

View File

@@ -0,0 +1,46 @@
import dependencyObservable = require("ui/core/dependency-observable");
import proxy = require("ui/core/proxy");
import common = require("ui/layouts/wrap-layout/wrap-layout-common");
// merge the exports of the common file with the exports of this file
declare var exports;
require("utils/module-merge").merge(common, exports);
export class WrapLayout extends common.WrapLayout {
static setNativeOrientationProperty(data: dependencyObservable.PropertyChangeData): void {
var wrapLayout = <WrapLayout>data.object;
var nativeView = wrapLayout._nativeView;
nativeView.setOrientation(data.newValue);
}
static setNativeItemWidthProperty(data: dependencyObservable.PropertyChangeData): void {
var wrapLayout = <WrapLayout>data.object;
var nativeView = wrapLayout._nativeView;
nativeView.setItemWidth(data.newValue);
}
static setNativeItemHeightProperty(data: dependencyObservable.PropertyChangeData): void {
var wrapLayout = <WrapLayout>data.object;
var nativeView = wrapLayout._nativeView;
nativeView.setItemHeight(data.newValue);
}
private _layout: org.nativescript.widgets.WrapLayout;
get android(): org.nativescript.widgets.WrapLayout {
return this._layout;
}
get _nativeView(): org.nativescript.widgets.WrapLayout {
return this._layout;
}
public _createUI() {
this._layout = new org.nativescript.widgets.WrapLayout(this._context);
}
}
(<proxy.PropertyMetadata>common.WrapLayout.orientationProperty.metadata).onSetNativeValue = WrapLayout.setNativeOrientationProperty;
(<proxy.PropertyMetadata>common.WrapLayout.orientationProperty.metadata).onSetNativeValue = WrapLayout.setNativeItemWidthProperty;
(<proxy.PropertyMetadata>common.WrapLayout.orientationProperty.metadata).onSetNativeValue = WrapLayout.setNativeItemHeightProperty;

View File

@@ -1,12 +1,12 @@
declare module "ui/layouts/wrap-layout" {
import layout = require("ui/layouts/layout");
import layout = require("ui/layouts/layout-base");
import dependencyObservable = require("ui/core/dependency-observable");
/**
* WrapLayout position children in rows or columns depending on orientation property
* until space is filled and then wraps them on new row or column.
*/
class WrapLayout extends layout.Layout {
class WrapLayout extends layout.LayoutBase {
/**
* Represents the observable property backing the orientation property of each WrapLayout instance.

View File

@@ -1,73 +1,20 @@
import layouts = require("ui/layouts/layout");
import definition = require("ui/layouts/wrap-layout");
import utils = require("utils/utils");
import dependencyObservable = require("ui/core/dependency-observable");
import utils = require("utils/utils");
import view = require("ui/core/view");
import enums = require("ui/enums");
import dependencyObservable = require("ui/core/dependency-observable");
import proxy = require("ui/core/proxy");
import common = require("ui/layouts/wrap-layout/wrap-layout-common");
function isWidthHeightValid(value: any): boolean {
return isNaN(value) || (value >= 0.0 && value !== Number.POSITIVE_INFINITY);
}
// merge the exports of the common file with the exports of this file
declare var exports;
require("utils/module-merge").merge(common, exports);
function isValidOrientation(value: any): boolean {
return value === enums.Orientation.vertical || value === enums.Orientation.horizontal;
}
export class WrapLayout extends layouts.Layout implements definition.WrapLayout {
export class WrapLayout extends common.WrapLayout {
private _lenghts: Array<number>;
public static orientationProperty = new dependencyObservable.Property(
"orientation",
"WrapLayout",
new proxy.PropertyMetadata(enums.Orientation.horizontal,
dependencyObservable.PropertyMetadataSettings.AffectsLayout,
undefined,
isValidOrientation)
);
public static itemWidthProperty = new dependencyObservable.Property(
"itemWidth",
"WrapLayout",
new proxy.PropertyMetadata(Number.NaN,
dependencyObservable.PropertyMetadataSettings.AffectsLayout,
undefined,
isWidthHeightValid)
);
public static itemHeightProperty = new dependencyObservable.Property(
"itemHeight",
"WrapLayout",
new proxy.PropertyMetadata(Number.NaN,
dependencyObservable.PropertyMetadataSettings.AffectsLayout,
undefined,
isWidthHeightValid)
);
get orientation(): string {
return this._getValue(WrapLayout.orientationProperty);
}
set orientation(value: string) {
this._setValue(WrapLayout.orientationProperty, value);
}
get itemWidth(): number {
return this._getValue(WrapLayout.itemWidthProperty);
}
set itemWidth(value: number) {
this._setValue(WrapLayout.itemWidthProperty, value);
}
get itemHeight(): number {
return this._getValue(WrapLayout.itemHeightProperty);
}
set itemHeight(value: number) {
this._setValue(WrapLayout.itemHeightProperty, value);
}
private static getChildMeasureSpec(parentMode: number, parentLength: number, itemLength): number {
if (!isNaN(itemLength)) {
if (itemLength > 0) {
return utils.layout.makeMeasureSpec(itemLength, utils.layout.EXACTLY);
}
else if (parentMode === utils.layout.UNSPECIFIED) {

View File

@@ -1,5 +1,4 @@
import dependencyObservable = require("ui/core/dependency-observable");
import view = require("ui/core/view");
import definition = require("ui/scroll-view");
import contentView = require("ui/content-view");
import common = require("ui/scroll-view/scroll-view-common");
@@ -8,97 +7,12 @@ import enums = require("ui/enums");
global.moduleMerge(common, exports);
var OWNER = "_owner";
var STATE = "_scrollViewState";
common.orientationProperty.metadata.onValueChanged = function scrollViewOrientationChanged(data: dependencyObservable.PropertyChangeData) {
(<ScrollView>data.object)._onOrientationChanged(data.oldValue, data.newValue);
}
interface ScrollViewState {
scrollX: number;
scrollY: number;
}
function onMeasureScrollView(widthMeasureSpec: number, heightMeasureSpec: number) {
var owner: view.View = this.owner;
owner.onMeasure(widthMeasureSpec, heightMeasureSpec);
this.setMeasuredDimension(owner.getMeasuredWidth(), owner.getMeasuredHeight());
}
function onLayoutScrollView(changed: boolean, left: number, top: number, right: number, bottom: number) {
var owner: view.View = this.owner;
owner.onLayout(left, top, right, bottom);
// Restore scroll state on the first layout after native instance is recreated.
var state: ScrollViewState = owner[STATE];
if (state) {
this.scrollTo(state.scrollX, state.scrollY);
delete owner[STATE];
}
}
function onSaveInstanceStateNative(): android.os.Parcelable {
var state: ScrollViewState = {
scrollX: this.getScrollX(),
scrollY: this.getScrollY()
}
this.owner[STATE] = state;
return this.super.onSaveInstanceState();
}
class NativeVerticalScrollView extends android.widget.ScrollView {
constructor(ctx) {
super(ctx);
return global.__native(this);
}
get owner() {
return this[OWNER];
}
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number) {
onMeasureScrollView.apply(this, [widthMeasureSpec, heightMeasureSpec]);
}
public onLayout(changed: boolean, left: number, top: number, right: number, bottom: number) {
onLayoutScrollView.apply(this, [changed, left, top, right, bottom]);
}
public onSaveInstanceState() {
onSaveInstanceStateNative.apply(this, []);
}
};
class NativeHorizontalScrollView extends android.widget.HorizontalScrollView {
constructor(ctx) {
super(ctx);
return global.__native(this);
}
get owner() {
return this[OWNER];
}
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number) {
onMeasureScrollView.apply(this, [widthMeasureSpec, heightMeasureSpec]);
}
public onLayout(changed: boolean, left: number, top: number, right: number, bottom: number) {
onLayoutScrollView.apply(this, [changed, left, top, right, bottom]);
}
public onSaveInstanceState() {
onSaveInstanceStateNative.apply(this, []);
}
};
export class ScrollView extends contentView.ContentView implements definition.ScrollView {
private _android: android.widget.FrameLayout;
private _contentMeasuredWidth: number = 0;
private _contentMeasuredHeight: number = 0;
private _scrollableLength: number = 0;
private _android: org.nativescript.widgets.VerticalScrollView | org.nativescript.widgets.HorizontalScrollView;
private _androidViewId: number;
get android(): android.view.ViewGroup {
@@ -137,7 +51,7 @@ export class ScrollView extends contentView.ContentView implements definition.Sc
return 0;
}
return this._scrollableLength;
return this._android.getScrollableLength();
}
get scrollableHeight(): number {
@@ -145,19 +59,18 @@ export class ScrollView extends contentView.ContentView implements definition.Sc
return 0;
}
return this._scrollableLength;
return this._android.getScrollableLength();
}
public scrollToVerticalOffset(value: number, animated: boolean) {
if (this._android && this.orientation === enums.Orientation.vertical) {
value *= utils.layout.getDisplayDensity();
var scrollView: android.widget.ScrollView = (<android.widget.ScrollView>this._android);
if (animated) {
scrollView.smoothScrollTo(0, value);
this._android.smoothScrollTo(0, value);
}
else {
scrollView.scrollTo(0, value);
this._android.scrollTo(0, value);
}
}
}
@@ -166,30 +79,28 @@ export class ScrollView extends contentView.ContentView implements definition.Sc
if (this._android && this.orientation === enums.Orientation.horizontal) {
value *= utils.layout.getDisplayDensity();
var scrollView: android.widget.HorizontalScrollView = (<android.widget.HorizontalScrollView>this._android);
if (animated) {
scrollView.smoothScrollTo(value, 0);
this._android.smoothScrollTo(value, 0);
}
else {
scrollView.scrollTo(value, 0);
this._android.scrollTo(value, 0);
}
}
}
public _createUI() {
if (this.orientation === enums.Orientation.horizontal) {
this._android = new NativeHorizontalScrollView(this._context);
this._android = new org.nativescript.widgets.HorizontalScrollView(this._context);
}
else {
this._android = new NativeVerticalScrollView(this._context);
this._android = new org.nativescript.widgets.VerticalScrollView(this._context);
}
if (!this._androidViewId) {
this._androidViewId = android.view.View.generateViewId();
}
this._android.setId(this._androidViewId);
this._android[OWNER] = this;
this._android.setId(this._androidViewId);
}
public _onOrientationChanged(oldValue: string, newValue: string) {
@@ -205,56 +116,4 @@ export class ScrollView extends contentView.ContentView implements definition.Sc
}
}
}
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
// Don't call measure because it will measure content twice.
var width = utils.layout.getMeasureSpecSize(widthMeasureSpec);
var widthMode = utils.layout.getMeasureSpecMode(widthMeasureSpec);
var height = utils.layout.getMeasureSpecSize(heightMeasureSpec);
var heightMode = utils.layout.getMeasureSpecMode(heightMeasureSpec);
var density = utils.layout.getDisplayDensity();
var child = this.content
if (!child) {
this._scrollableLength = 0;
this._contentMeasuredWidth = this.minWidth * density;
this._contentMeasuredHeight = this.minHeight * density;
}
else {
var childSize: { measuredWidth: number; measuredHeight: number };
if (this.orientation === enums.Orientation.vertical) {
childSize = view.View.measureChild(this, child, widthMeasureSpec, utils.layout.makeMeasureSpec(0, utils.layout.UNSPECIFIED));
}
else {
childSize = view.View.measureChild(this, child, utils.layout.makeMeasureSpec(0, utils.layout.UNSPECIFIED), heightMeasureSpec);
}
this._contentMeasuredWidth = Math.max(childSize.measuredWidth, this.minWidth * density);
this._contentMeasuredHeight = Math.max(childSize.measuredHeight, this.minHeight * density);
}
var widthAndState = view.View.resolveSizeAndState(this._contentMeasuredWidth, width, widthMode, 0);
var heightAndState = view.View.resolveSizeAndState(this._contentMeasuredHeight, height, heightMode, 0);
this.setMeasuredDimension(widthAndState, heightAndState);
}
public onLayout(left: number, top: number, right: number, bottom: number): void {
var width = (right - left);
var height = (bottom - top);
if (this.orientation === enums.Orientation.horizontal) {
this._scrollableLength = this._contentMeasuredWidth - width;
view.View.layoutChild(this, this.content, 0, 0, Math.max(this._contentMeasuredWidth, width), height);
}
else {
this._scrollableLength = this._contentMeasuredHeight - height;
view.View.layoutChild(this, this.content, 0, 0, width, Math.max(this._contentMeasuredHeight, height));
}
this._scrollableLength /= utils.layout.getDisplayDensity();
this._scrollableLength = Math.max(0, this._scrollableLength);
}
}

View File

@@ -23,6 +23,216 @@ var _handlersCache = {};
// classes like Frame that does not need to handle styling properties.
var noStylingClasses = {};
// on Android we explicitly set propertySettings to None because android will invalidate its layout (skip unnecessary native call).
var AffectsLayout = global.android ? dependencyObservable.PropertyMetadataSettings.None : dependencyObservable.PropertyMetadataSettings.AffectsLayout;
export interface Thickness {
left: number;
top: number;
right: number;
bottom: number;
}
export interface CommonLayoutParams {
width: number;
height: number;
leftMargin: number;
topMargin: number;
rightMargin: number;
bottomMargin: number;
horizontalAlignment: string;
verticalAlignment: string;
}
function parseThickness(value: any): Thickness {
var result: Thickness = { top: 0, right: 0, bottom: 0, left: 0 };
if (types.isString(value)) {
var arr = value.split(/[ ,]+/);
var top = parseInt(arr[0]);
top = isNaN(top) ? 0 : top;
var right = parseInt(arr[1]);
right = isNaN(right) ? top : right;
var bottom = parseInt(arr[2]);
bottom = isNaN(bottom) ? top : bottom;
var left = parseInt(arr[3]);
left = isNaN(left) ? right : left;
result.top = top;
result.right = right;
result.bottom = bottom;
result.left = left;
} else if (types.isNumber(value)) {
result.top = result.right = result.bottom = result.left = value;
}
return result;
}
function layoutParamsComparer(x: CommonLayoutParams, y: CommonLayoutParams): boolean {
return x.width === y.width
&& x.height === y.height
&& x.leftMargin === y.leftMargin
&& x.topMargin === y.topMargin
&& x.rightMargin === y.rightMargin
&& x.bottomMargin === y.bottomMargin
&& x.horizontalAlignment === y.horizontalAlignment
&& x.verticalAlignment === y.verticalAlignment
}
function onLayoutParamsChanged(data: observable.PropertyChangeData) {
var style = <Style>data.object;
var layoutParams: CommonLayoutParams = {
width: isNaN(style.width) ? -1 : style.width,
height: isNaN(style.height) ? -1 : style.height,
leftMargin: style.marginLeft,
topMargin: style.marginTop,
rightMargin: style.marginRight,
bottomMargin: style.marginBottom,
horizontalAlignment: style.horizontalAlignment,
verticalAlignment: style.verticalAlignment
};
style._setValue(nativeLayoutParamsProperty, layoutParams);
}
function onPaddingValueChanged(data: observable.PropertyChangeData) {
var style = <Style>data.object;
var thickness: Thickness = {
top: style.paddingTop,
right: style.paddingRight,
bottom: style.paddingBottom,
left: style.paddingLeft
};
style._setValue(nativePaddingsProperty, thickness);
}
function onPaddingChanged(data: observable.PropertyChangeData) {
var thickness = parseThickness(data.newValue);
var style = <Style>data.object;
var valueSource = style._getValueSource(paddingProperty);
style._setValue(paddingTopProperty, thickness.top, valueSource);
style._setValue(paddingRightProperty, thickness.right, valueSource);
style._setValue(paddingBottomProperty, thickness.bottom, valueSource);
style._setValue(paddingLeftProperty, thickness.left, valueSource);
}
function onMarginChanged(data: observable.PropertyChangeData) {
var thickness = parseThickness(data.newValue);
var style = <Style>data.object;
var valueSource = style._getValueSource(marginProperty);
style._setValue(marginTopProperty, thickness.top, valueSource);
style._setValue(marginRightProperty, thickness.right, valueSource);
style._setValue(marginBottomProperty, thickness.bottom, valueSource);
style._setValue(marginLeftProperty, thickness.left, valueSource);
}
function thicknessComparer(x: Thickness, y: Thickness): boolean {
return x.left === y.left && x.top === y.top && x.right === y.right && x.bottom === y.bottom;
}
function isWidthHeightValid(value: number): boolean {
return isNaN(value) || (value >= 0.0 && isFinite(value));
}
function isMinWidthHeightValid(value: number): boolean {
return !isNaN(value) && value >= 0.0 && isFinite(value);
}
function onBackgroundImagePropertyChanged(data: observable.PropertyChangeData) {
var view: view.View = (<any>data.object)._view;
var style = <Style>data.object;
var url: string = data.newValue;
style._setValue(backgroundImageSourceProperty, undefined, observable.ValueSource.Local);
if (types.isString(data.newValue)) {
var pattern: RegExp = /url\(('|")(.*?)\1\)/;
var match = url.match(pattern);
if (match && match[2]) {
url = match[2];
}
if (utils.isDataURI(url)) {
var base64Data = url.split(",")[1];
if (types.isDefined(base64Data)) {
style._setValue(backgroundImageSourceProperty, imageSource.fromBase64(base64Data), observable.ValueSource.Local);
}
} else if (utils.isFileOrResourcePath(url)) {
style._setValue(backgroundImageSourceProperty, imageSource.fromFileOrResource(url), observable.ValueSource.Local);
} else if (url.indexOf("http") !== -1) {
if (view) {
view["_url"] = url;
}
imageSource.fromUrl(url).then(r=> {
if (view && view["_url"] === url) {
style._setValue(backgroundImageSourceProperty, r, observable.ValueSource.Local);
}
});
}
}
}
function getHandlerInternal(propertyId: number, classInfo: types.ClassInfo): styling.stylers.StylePropertyChangedHandler {
var className = classInfo ? classInfo.name : "default";
var handlerKey = className + propertyId;
// try the cache first
var result = _handlersCache[handlerKey];
if (types.isDefined(result)) {
return result;
}
var propertyHandlers = _registeredHandlers[propertyId];
if (noStylingClasses.hasOwnProperty(className) || !propertyHandlers) {
// Reached 'no-styling' class or no property handlers are registered for this proeprtyID
result = null;
}
else if (propertyHandlers.hasOwnProperty(className)) {
// Found handler for this class
result = propertyHandlers[className];
}
else if (classInfo) {
// Check the base class
result = getHandlerInternal(propertyId, classInfo.baseClassInfo);
}
else {
result = null;
}
_handlersCache[handlerKey] = result;
return result;
}
function isVisibilityValid(value: string): boolean {
return value === enums.Visibility.visible || value === enums.Visibility.collapse || value === enums.Visibility.collapsed;
}
function onVisibilityChanged(data: observable.PropertyChangeData) {
(<any>data.object)._view._isVisibleCache = data.newValue === enums.Visibility.visible;
}
function isPaddingValid(value: number): boolean {
return isFinite(value) && !isNaN(value) && value >= 0;
}
function isMarginValid(value: number): boolean {
return isFinite(value) && !isNaN(value);
}
function isOpacityValid(value: string): boolean {
var parsedValue: number = parseFloat(value);
return !isNaN(parsedValue) && 0 <= parsedValue && parsedValue <= 1;
}
export class Style extends observable.DependencyObservable implements styling.Style {
private _view: view.View;
private _updateCounter = 0;
@@ -263,7 +473,7 @@ export class Style extends observable.DependencyObservable implements styling.St
super();
this._view = parentView;
}
public _beginUpdate() {
this._updateCounter++;
}
@@ -274,9 +484,9 @@ export class Style extends observable.DependencyObservable implements styling.St
throw new Error("style._endUpdate() called, but no update is in progress.");
}
if (this._updateCounter === 0) {
this._nativeSetters.forEach((newValue, property, map) => { this._applyStyleProperty(property, newValue); });
this._nativeSetters.clear();
}
this._nativeSetters.forEach((newValue, property, map) => { this._applyStyleProperty(property, newValue); });
this._nativeSetters.clear();
}
}
public _resetCssValues() {
@@ -400,9 +610,7 @@ export class Style extends observable.DependencyObservable implements styling.St
}
}
export function registerHandler(property: dependencyObservable.Property,
handler: styling.stylers.StylePropertyChangedHandler,
className?: string) {
export function registerHandler(property: dependencyObservable.Property, handler: styling.stylers.StylePropertyChangedHandler, className?: string) {
var realClassName = className ? className : "default";
var handlerRecord = _registeredHandlers[property.id];
@@ -422,37 +630,6 @@ export function getHandler(property: dependencyObservable.Property, view: view.V
return getHandlerInternal(property.id, types.getClassInfo(view));
}
function getHandlerInternal(propertyId: number, classInfo: types.ClassInfo): styling.stylers.StylePropertyChangedHandler {
var className = classInfo ? classInfo.name : "default";
var handlerKey = className + propertyId;
// try the cache first
var result = _handlersCache[handlerKey];
if (types.isDefined(result)) {
return result;
}
var propertyHandlers = _registeredHandlers[propertyId];
if (noStylingClasses.hasOwnProperty(className) || !propertyHandlers) {
// Reached 'no-styling' class or no property handlers are registered for this proeprtyID
result = null;
}
else if (propertyHandlers.hasOwnProperty(className)) {
// Found handler for this class
result = propertyHandlers[className];
}
else if (classInfo) {
// Check the base class
result = getHandlerInternal(propertyId, classInfo.baseClassInfo);
}
else {
result = null;
}
_handlersCache[handlerKey] = result;
return result;
}
// Property registration
export var colorProperty = new styleProperty.Property("color", "color",
new observable.PropertyMetadata(undefined, observable.PropertyMetadataSettings.Inheritable, undefined, color.Color.isValid, color.Color.equals),
@@ -574,7 +751,7 @@ export var fontWeightProperty = new styleProperty.Property("fontWeight", "font-w
new observable.PropertyMetadata(enums.FontWeight.normal, observable.PropertyMetadataSettings.Inheritable, onFontWeightChanged, isFontWeightValid));
export var fontInternalProperty = new styleProperty.Property("_fontInternal", "_fontInternal",
new observable.PropertyMetadata(font.Font.default, observable.PropertyMetadataSettings.AffectsLayout, null, null, font.Font.equals), font.Font.parse);
new observable.PropertyMetadata(font.Font.default, AffectsLayout, null, null, font.Font.equals), font.Font.parse);
function isFontWeightValid(value: string): boolean {
return value === enums.FontWeight.normal || value === enums.FontWeight.bold;
@@ -632,149 +809,77 @@ function onFontChanged(data: observable.PropertyChangeData) {
}
export var textAlignmentProperty = new styleProperty.Property("textAlignment", "text-align",
new observable.PropertyMetadata(undefined, observable.PropertyMetadataSettings.AffectsLayout | observable.PropertyMetadataSettings.Inheritable),
converters.textAlignConverter);
function isWidthHeightValid(value: number): boolean {
return isNaN(value) || (value >= 0.0 && isFinite(value));
}
function isMinWidthHeightValid(value: number): boolean {
return !isNaN(value) && value >= 0.0 && isFinite(value);
}
export var widthProperty = new styleProperty.Property("width", "width",
new observable.PropertyMetadata(
Number.NaN, observable.PropertyMetadataSettings.AffectsLayout, null, isWidthHeightValid),
converters.numberConverter);
export var heightProperty = new styleProperty.Property("height", "height",
new observable.PropertyMetadata(
Number.NaN, observable.PropertyMetadataSettings.AffectsLayout, null, isWidthHeightValid),
converters.numberConverter);
new observable.PropertyMetadata(undefined, AffectsLayout | observable.PropertyMetadataSettings.Inheritable), converters.textAlignConverter);
export var minWidthProperty = new styleProperty.Property("minWidth", "min-width",
new observable.PropertyMetadata(
0, observable.PropertyMetadataSettings.AffectsLayout, null, isMinWidthHeightValid),
converters.numberConverter);
new observable.PropertyMetadata(0, AffectsLayout, null, isMinWidthHeightValid), converters.numberConverter);
export var minHeightProperty = new styleProperty.Property("minHeight", "min-height",
new observable.PropertyMetadata(
0, observable.PropertyMetadataSettings.AffectsLayout, null, isMinWidthHeightValid),
converters.numberConverter);
new observable.PropertyMetadata(0, AffectsLayout, null, isMinWidthHeightValid), converters.numberConverter);
function parseThickness(value: any): { top: number; right: number; bottom: number; left: number } {
var result = { top: 0, right: 0, bottom: 0, left: 0 };
if (types.isString(value)) {
var arr = value.split(/[ ,]+/);
var top = parseInt(arr[0]);
top = isNaN(top) ? 0 : top;
// Helper property holding most layout related properties available in CSS.
// When layout related properties are set in CSS we chache them and send them to the native view in a single call.
export var nativeLayoutParamsProperty = new styleProperty.Property("nativeLayoutParams", "nativeLayoutParams",
new observable.PropertyMetadata({
width: -1,
height: -1,
leftMargin: 0,
topMargin: 0,
rightMargin: 0,
bottomMargin: 0,
horizontalAlignment: enums.HorizontalAlignment.stretch,
verticalAlignment: enums.VerticalAlignment.stretch
}, null, null, null, layoutParamsComparer));
var right = parseInt(arr[1]);
right = isNaN(right) ? top : right;
// Helper property holding all paddings. When paddings are set through CSS we cache them and send them to the native view in a single call.
export var nativePaddingsProperty = new styleProperty.Property("paddingNative", "paddingNative",
new observable.PropertyMetadata({ top: 0, right: 0, bottom: 0, left: 0 }, null, null, null, thicknessComparer));
var bottom = parseInt(arr[2]);
bottom = isNaN(bottom) ? top : bottom;
export var widthProperty = new styleProperty.Property("width", "width",
new observable.PropertyMetadata(Number.NaN, AffectsLayout, onLayoutParamsChanged, isWidthHeightValid), converters.numberConverter);
var left = parseInt(arr[3]);
left = isNaN(left) ? right : left;
result.top = top;
result.right = right;
result.bottom = bottom;
result.left = left;
} else if (types.isNumber(value)) {
result.top = result.right = result.bottom = result.left = value;
}
return result;
}
function onPaddingChanged(data: observable.PropertyChangeData) {
var thickness = parseThickness(data.newValue);
var style = <Style>data.object;
style.paddingTop = thickness.top;
style.paddingRight = thickness.right;
style.paddingBottom = thickness.bottom;
style.paddingLeft = thickness.left;
}
function onMarginChanged(data: observable.PropertyChangeData) {
var thickness = parseThickness(data.newValue);
var style = <Style>data.object;
style.marginTop = thickness.top;
style.marginRight = thickness.right;
style.marginBottom = thickness.bottom;
style.marginLeft = thickness.left;
}
export var heightProperty = new styleProperty.Property("height", "height",
new observable.PropertyMetadata(Number.NaN, AffectsLayout, onLayoutParamsChanged, isWidthHeightValid), converters.numberConverter);
export var verticalAlignmentProperty = new styleProperty.Property("verticalAlignment", "vertical-align",
new observable.PropertyMetadata(enums.VerticalAlignment.stretch, observable.PropertyMetadataSettings.AffectsLayout));
new observable.PropertyMetadata(enums.VerticalAlignment.stretch, AffectsLayout, onLayoutParamsChanged));
export var horizontalAlignmentProperty = new styleProperty.Property("horizontalAlignment", "horizontal-align",
new observable.PropertyMetadata(enums.HorizontalAlignment.stretch, observable.PropertyMetadataSettings.AffectsLayout));
new observable.PropertyMetadata(enums.HorizontalAlignment.stretch, AffectsLayout, onLayoutParamsChanged));
export var marginProperty = new styleProperty.Property("margin", "margin",
new observable.PropertyMetadata(null, null, onMarginChanged));
export var paddingProperty = new styleProperty.Property("padding", "padding",
new observable.PropertyMetadata(null, null, onPaddingChanged));
export var marginProperty = new styleProperty.Property("margin", "margin", new observable.PropertyMetadata(null, null, onMarginChanged));
export var marginLeftProperty = new styleProperty.Property("marginLeft", "margin-left",
new observable.PropertyMetadata(0, observable.PropertyMetadataSettings.AffectsLayout, null, isMarginValid), converters.numberConverter);
new observable.PropertyMetadata(0, AffectsLayout, onLayoutParamsChanged, isMarginValid), converters.numberConverter);
export var marginRightProperty = new styleProperty.Property("marginRight", "margin-right",
new observable.PropertyMetadata(0, observable.PropertyMetadataSettings.AffectsLayout, null, isMarginValid), converters.numberConverter);
new observable.PropertyMetadata(0, AffectsLayout, onLayoutParamsChanged, isMarginValid), converters.numberConverter);
export var marginTopProperty = new styleProperty.Property("marginTop", "margin-top",
new observable.PropertyMetadata(0, observable.PropertyMetadataSettings.AffectsLayout, null, isMarginValid), converters.numberConverter);
new observable.PropertyMetadata(0, AffectsLayout, onLayoutParamsChanged, isMarginValid), converters.numberConverter);
export var marginBottomProperty = new styleProperty.Property("marginBottom", "margin-bottom",
new observable.PropertyMetadata(0, observable.PropertyMetadataSettings.AffectsLayout, null, isMarginValid), converters.numberConverter);
new observable.PropertyMetadata(0, AffectsLayout, onLayoutParamsChanged, isMarginValid), converters.numberConverter);
export var paddingProperty = new styleProperty.Property("padding", "padding", new observable.PropertyMetadata(null, null, onPaddingChanged));
export var paddingLeftProperty = new styleProperty.Property("paddingLeft", "padding-left",
new observable.PropertyMetadata(0, observable.PropertyMetadataSettings.AffectsLayout, null, isPaddingValid), converters.numberConverter);
new observable.PropertyMetadata(0, AffectsLayout, onPaddingValueChanged, isPaddingValid), converters.numberConverter);
export var paddingRightProperty = new styleProperty.Property("paddingRight", "padding-right",
new observable.PropertyMetadata(0, observable.PropertyMetadataSettings.AffectsLayout, null, isPaddingValid), converters.numberConverter);
new observable.PropertyMetadata(0, AffectsLayout, onPaddingValueChanged, isPaddingValid), converters.numberConverter);
export var paddingTopProperty = new styleProperty.Property("paddingTop", "padding-top",
new observable.PropertyMetadata(0, observable.PropertyMetadataSettings.AffectsLayout, null, isPaddingValid), converters.numberConverter);
new observable.PropertyMetadata(0, AffectsLayout, onPaddingValueChanged, isPaddingValid), converters.numberConverter);
export var paddingBottomProperty = new styleProperty.Property("paddingBottom", "padding-bottom",
new observable.PropertyMetadata(0, observable.PropertyMetadataSettings.AffectsLayout, null, isPaddingValid), converters.numberConverter);
function isVisibilityValid(value: string): boolean {
return value === enums.Visibility.visible || value === enums.Visibility.collapse || value === enums.Visibility.collapsed;
}
function setLayoutInfoVisibility(data: observable.PropertyChangeData) {
(<any>data.object)._view._isVisibleCache = (data.newValue === enums.Visibility.visible);
}
new observable.PropertyMetadata(0, AffectsLayout, onPaddingValueChanged, isPaddingValid), converters.numberConverter);
export var visibilityProperty = new styleProperty.Property("visibility", "visibility",
new observable.PropertyMetadata(enums.Visibility.visible, observable.PropertyMetadataSettings.AffectsLayout, setLayoutInfoVisibility, isVisibilityValid),
converters.visibilityConverter);
function isPaddingValid(value: number): boolean {
return isFinite(value) && !isNaN(value) && value >= 0;
}
function isMarginValid(value: number): boolean {
return isFinite(value) && !isNaN(value);
}
function isOpacityValid(value: string): boolean {
var parsedValue: number = parseFloat(value);
return !isNaN(parsedValue) && 0 <= parsedValue && parsedValue <= 1;
}
new observable.PropertyMetadata(enums.Visibility.visible, AffectsLayout, onVisibilityChanged, isVisibilityValid), converters.visibilityConverter);
export var opacityProperty = new styleProperty.Property("opacity", "opacity",
new observable.PropertyMetadata(1.0, observable.PropertyMetadataSettings.None, undefined, isOpacityValid),
converters.opacityConverter);
new observable.PropertyMetadata(1.0, observable.PropertyMetadataSettings.None, undefined, isOpacityValid), converters.opacityConverter);
// register default stylers once all properties are defined.
stylers._registerDefaultStylers();

View File

@@ -50,7 +50,7 @@ function onBackgroundOrBorderPropertyChanged(v: view.View) {
v.android.setBackgroundDrawable(_defaultBackgrounds.get(viewClass));
}
}
}
}
export class DefaultStyler implements definition.stylers.Styler {
//Background and borders methods
@@ -99,6 +99,94 @@ export class DefaultStyler implements definition.stylers.Styler {
(<android.view.View>view._nativeView).setMinimumHeight(0);
}
private static setNativeLayoutParamsProperty(view: view.View, params: style.CommonLayoutParams): void {
var nativeView: android.view.View = view._nativeView;
var lp = <org.nativescript.widgets.CommonLayoutParams>nativeView.getLayoutParams();
if (!(lp instanceof org.nativescript.widgets.CommonLayoutParams)) {
lp = new org.nativescript.widgets.CommonLayoutParams();
}
lp.leftMargin = params.leftMargin * utils.layout.getDisplayDensity();
lp.topMargin = params.topMargin * utils.layout.getDisplayDensity();
lp.rightMargin = params.rightMargin * utils.layout.getDisplayDensity();
lp.bottomMargin = params.bottomMargin * utils.layout.getDisplayDensity();
var width = params.width * utils.layout.getDisplayDensity();
var height = params.height * utils.layout.getDisplayDensity();
// If width is not specified set it as WRAP_CONTENT
if (width < 0) {
width = -2;
}
// If height is not specified set it as WRAP_CONTENT
if (lp.height < 0) {
lp.height = -2;
}
var gravity = 0;
switch (params.horizontalAlignment) {
case enums.HorizontalAlignment.left:
gravity |= android.view.Gravity.LEFT;
break;
case enums.HorizontalAlignment.center:
gravity |= android.view.Gravity.CENTER_HORIZONTAL;
break;
case enums.HorizontalAlignment.right:
gravity |= android.view.Gravity.RIGHT;
break;
case enums.HorizontalAlignment.stretch:
gravity |= android.view.Gravity.FILL_HORIZONTAL;
// If width is not specified set it as MATCH_PARENT
if (width < 0) {
width = -1;
}
break;
default:
throw new Error("Invalid horizontalAlignment value: " + params.horizontalAlignment);
}
switch (params.verticalAlignment) {
case enums.VerticalAlignment.top:
gravity |= android.view.Gravity.TOP;
break;
case enums.VerticalAlignment.center:
gravity |= android.view.Gravity.CENTER_VERTICAL;
break;
case enums.VerticalAlignment.bottom:
gravity |= android.view.Gravity.BOTTOM;
break;
case enums.VerticalAlignment.stretch:
gravity |= android.view.Gravity.FILL_VERTICAL;
// If height is not specified set it as MATCH_PARENT
if (height < 0) {
height = -1;
}
break;
default:
throw new Error("Invalid verticalAlignment value: " + params.verticalAlignment);
}
lp.width = width;
lp.height = height;
lp.gravity = gravity;
nativeView.setLayoutParams(lp);
}
private static resetNativeLayoutParamsProperty(view: view.View, nativeValue: any): void {
var nativeView: android.view.View = view._nativeView;
nativeView.setLayoutParams(new org.nativescript.widgets.CommonLayoutParams());
}
public static registerHandlers() {
style.registerHandler(style.visibilityProperty, new stylersCommon.StylePropertyChangedHandler(
DefaultStyler.setVisibilityProperty,
@@ -126,6 +214,10 @@ export class DefaultStyler implements definition.stylers.Styler {
style.registerHandler(style.borderWidthProperty, borderHandler);
style.registerHandler(style.borderColorProperty, borderHandler);
style.registerHandler(style.borderRadiusProperty, borderHandler);
style.registerHandler(style.nativeLayoutParamsProperty, new stylersCommon.StylePropertyChangedHandler(
DefaultStyler.setNativeLayoutParamsProperty,
DefaultStyler.resetNativeLayoutParamsProperty));
}
}
@@ -158,7 +250,7 @@ export class TextViewStyler implements definition.stylers.Styler {
if (fontValue.fontSize) {
tv.setTextSize(fontValue.fontSize);
}
}
else {
tv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, nativeValue.size);
}
@@ -368,6 +460,28 @@ export class SearchBarStyler implements definition.stylers.Styler {
}
}
export class LayoutBaseStyler implements definition.stylers.Styler {
//nativePadding methods
private static setPaddingNativeProperty(view: view.View, newValue: style.Thickness): void {
var left = (newValue.left * utils.layout.getDisplayDensity());
var top = (newValue.top * utils.layout.getDisplayDensity());
var right = (newValue.right * utils.layout.getDisplayDensity());
var bottom = (newValue.bottom * utils.layout.getDisplayDensity());
(<android.view.View>view._nativeView).setPadding(left, top, right, bottom);
}
private static resetPaddingNativeProperty(view: view.View, nativeValue: any): void {
(<android.view.View>view._nativeView).setPadding(0, 0, 0, 0);
}
public static registerHandlers() {
style.registerHandler(style.nativePaddingsProperty, new stylersCommon.StylePropertyChangedHandler(
LayoutStyler.setPaddingNativeProperty,
LayoutStyler.resetPaddingNativeProperty), "Layout");
}
}
// Register all styler at the end.
export function _registerDefaultStylers() {
style.registerNoStylingClass("Frame");
@@ -376,4 +490,5 @@ export function _registerDefaultStylers() {
ActivityIndicatorStyler.registerHandlers();
SegmentedBarStyler.registerHandlers();
SearchBarStyler.registerHandlers();
LayoutBaseStyler.registerHandlers();
}

View File

@@ -26,9 +26,4 @@ export function greaterThanZero(value: Object): boolean {
export function notNegative(value: Object): boolean {
return (<number>value) >= 0;
}
export function isFiniteNumber(value: Object): boolean {
var num = <number>value;
return isFinite(num);
}
}

View File

@@ -31,6 +31,7 @@ export module layout {
export var MEASURED_STATE_TOO_SMALL = 0x01000000;
export var MEASURED_STATE_MASK = 0xff000000;
export var MEASURED_SIZE_MASK = 0x00ffffff;
export function getMode(mode: number): string {
switch (mode) {

4
utils/utils.d.ts vendored
View File

@@ -8,6 +8,10 @@
* Utility module related to layout.
*/
module layout {
/**
* Bits that provide the actual measured size.
*/
export var MEASURED_SIZE_MASK: number;
export var MEASURED_STATE_MASK: number;
export var MEASURED_STATE_TOO_SMALL: number;
export var UNSPECIFIED: number;