diff --git a/CrossPlatformModules.csproj b/CrossPlatformModules.csproj
index 5344348f3..7acaf01a7 100644
--- a/CrossPlatformModules.csproj
+++ b/CrossPlatformModules.csproj
@@ -217,13 +217,19 @@
+
+
+ layout-helper.d.ts
+
-
+
+ layout-helper.d.ts
+
diff --git a/android17.d.ts b/android17.d.ts
index 2166aee83..a037485ed 100644
--- a/android17.d.ts
+++ b/android17.d.ts
@@ -117006,7 +117006,12 @@ declare module android {
ContentDescription: string;
MinimumHeight: number;
DrawingCacheQuality: number;
- toString(): string;
+ toString(): string;
+
+ protected onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void;
+
+ protected onLayout(changed: boolean, left: number, top: number, right: number, bottom: number): void;
+
/**
* Returns the size of the vertical faded edges used to indicate that more content in this view is visible.
*/
diff --git a/apps/tests/layouts/layout-helper.android.ts b/apps/tests/layouts/layout-helper.android.ts
new file mode 100644
index 000000000..359de09b9
--- /dev/null
+++ b/apps/tests/layouts/layout-helper.android.ts
@@ -0,0 +1,120 @@
+import button = require("ui/button");
+import utils = require("utils/utils");
+import TKUnit = require("../TKUnit");
+
+var DELTA = 0.1;
+
+class NativeButton extends android.widget.Button {
+
+ private owner: MyButton;
+
+ constructor(context: android.content.Context, owner: MyButton) {
+ super(context);
+ this.owner = owner;
+ return global.__native(this);
+ }
+
+ protected onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ this.owner._measureWidth = utils.layout.getMeasureSpecSize(widthMeasureSpec);
+ this.owner._measureHeight = utils.layout.getMeasureSpecSize(heightMeasureSpec);
+ this.owner.measureCount++;
+ }
+
+ protected onLayout(changed: boolean, left: number, top: number, right: number, bottom: number): void {
+ this.owner._layoutLeft = left;
+ this.owner._layoutTop = top;
+ this.owner._layoutWidth = right - left;
+ this.owner._layoutHeight = bottom - top;
+
+ super.onLayout(changed, left, top, right, bottom);
+ this.owner.arrangeCount++;
+ }
+}
+
+export class MyButton extends button.Button {
+ public measureCount: number = 0;
+ public arrangeCount: number = 0;
+
+ _layoutLeft;
+ _layoutTop;
+ _layoutWidth;
+ _layoutHeight;
+
+ _measureWidth;
+ _measureHeight;
+
+ public get measured(): boolean {
+ return this.measureCount > 0;
+ }
+
+ public get arranged(): boolean {
+ return this.arrangeCount > 0;
+ }
+
+ private _layout: NativeButton;
+
+ get android(): NativeButton {
+ return this._layout;
+ }
+
+ get _nativeView(): NativeButton {
+ return this._layout;
+ }
+
+ public _createUI() {
+ this._layout = new NativeButton(this._context, this);
+ }
+
+ get measureHeight(): number {
+ return this._measureHeight;
+ }
+
+ get measureWidth(): number {
+ return this._measureWidth;
+ }
+
+ get layoutWidth(): number {
+ return this._layoutWidth;
+ }
+
+ get layoutHeight(): number {
+ return this._layoutHeight;
+ }
+
+ get layoutLeft(): number {
+ return this._layoutLeft;
+ }
+
+ get layoutTop(): number {
+ return this._layoutTop;
+ }
+}
+
+export function assertMeasure(btn: MyButton, width: number, height: number, name?: string) {
+ var density = utils.layout.getDisplayDensity();
+
+ var delta = Math.floor(density) !== density ? 1.1 : DELTA;
+ name = name ? "[" + name + "]" : "";
+
+ TKUnit.assertAreClose(Math.floor(btn.measureWidth / density), width, delta, name + "width");
+ TKUnit.assertAreClose(Math.floor(btn.measureHeight / density), height, delta, name + "height");
+}
+
+export function assertLayout(btn: MyButton, left: number, top: number, width: number, height: number, name?: string): void {
+ var density = utils.layout.getDisplayDensity();
+
+ var delta = Math.floor(density) !== density ? 1.1 : DELTA;
+ name = name ? "[" + name + "]" : "";
+
+ TKUnit.assertAreClose(Math.floor(btn.layoutLeft / density), left, delta, name + "left");
+ TKUnit.assertAreClose(Math.floor(btn.layoutTop / density), top, delta, name + "top");
+ TKUnit.assertAreClose(Math.floor(btn.layoutWidth / density), width, delta, name + "width");
+ TKUnit.assertAreClose(Math.floor(btn.layoutHeight / density), height, delta, name + "height");
+}
+
+export function dip(value: number): number {
+ var density = utils.layout.getDisplayDensity();
+ return Math.floor(value * density);
+}
\ No newline at end of file
diff --git a/apps/tests/layouts/layout-helper.ts b/apps/tests/layouts/layout-helper.ios.ts
similarity index 100%
rename from apps/tests/layouts/layout-helper.ts
rename to apps/tests/layouts/layout-helper.ios.ts
diff --git a/apps/tests/layouts/stack-layout-tests.ts b/apps/tests/layouts/stack-layout-tests.ts
index a63484767..b4dde9a90 100644
--- a/apps/tests/layouts/stack-layout-tests.ts
+++ b/apps/tests/layouts/stack-layout-tests.ts
@@ -217,7 +217,7 @@ export function test_insertChildAtPosition() {
let newChild = new Button();
newChild.text = 'in-between';
- rootLayout.insertChild(1, newChild);
+ rootLayout.insertChild(newChild, 1);
assertChildTexts("btn1|in-between|btn2", rootLayout, "button inserted at correct location");
}
diff --git a/ui/core/view-common.ts b/ui/core/view-common.ts
index bc83e1d43..00d0701da 100644
--- a/ui/core/view-common.ts
+++ b/ui/core/view-common.ts
@@ -777,7 +777,7 @@ export class View extends proxy.ProxyObject implements definition.View {
* Core logic for adding a child view to this instance. Used by the framework to handle lifecycle events more centralized. Do not outside the UI Stack implementation.
* // TODO: Think whether we need the base Layout routine.
*/
- public _addView(view: View) {
+ public _addView(view: View, atIndex?: number) {
if (!view) {
throw new Error("Expecting a valid View instance.");
}
@@ -787,7 +787,7 @@ export class View extends proxy.ProxyObject implements definition.View {
}
view._parent = this;
- this._addViewCore(view);
+ this._addViewCore(view, atIndex);
trace.write("called _addView on view " + this._domId + " for a child " + view._domId, trace.categories.ViewHierarchy);
}
@@ -795,13 +795,13 @@ export class View extends proxy.ProxyObject implements definition.View {
/**
* Method is intended to be overridden by inheritors and used as "protected"
*/
- public _addViewCore(view: View) {
+ public _addViewCore(view: View, atIndex?: number) {
this._propagateInheritableProperties(view);
view.style._inheritStyleProperties();
if (!view._isAddedToNativeVisualTree) {
- view._isAddedToNativeVisualTree = this._addViewToNativeVisualTree(view);
+ view._isAddedToNativeVisualTree = this._addViewToNativeVisualTree(view, atIndex);
}
// TODO: Discuss this.
@@ -874,7 +874,7 @@ export class View extends proxy.ProxyObject implements definition.View {
/**
* Method is intended to be overridden by inheritors and used as "protected".
*/
- public _addViewToNativeVisualTree(view: View): boolean {
+ public _addViewToNativeVisualTree(view: View, atIndex?: number): boolean {
if (view._isAddedToNativeVisualTree) {
throw new Error("Child already added to the native visual tree.");
}
diff --git a/ui/core/view.android.ts b/ui/core/view.android.ts
index 94e30ade3..22e9ec740 100644
--- a/ui/core/view.android.ts
+++ b/ui/core/view.android.ts
@@ -5,6 +5,7 @@ import utils = require("utils/utils");
import dependencyObservable = require("ui/core/dependency-observable");
import proxy = require("ui/core/proxy");
import gestures = require("ui/gestures");
+import types = require("utils/types");
global.moduleMerge(viewCommon, exports);
@@ -336,11 +337,16 @@ export class CustomLayoutView extends View implements viewDefinition.CustomLayou
this._viewGroup = new org.nativescript.widgets.ContentLayout(this._context);
}
- public _addViewToNativeVisualTree(child: View): boolean {
+ public _addViewToNativeVisualTree(child: View, atIndex?: number): boolean {
super._addViewToNativeVisualTree(child);
if (this._nativeView && child._nativeView) {
- this._nativeView.addView(child._nativeView);
+ if (types.isNullOrUndefined(atIndex) || atIndex >= this._nativeView.getChildCount()) {
+ this._nativeView.addView(child._nativeView);
+ }
+ else {
+ this._nativeView.addView(child._nativeView, atIndex);
+ }
return true;
}
diff --git a/ui/core/view.d.ts b/ui/core/view.d.ts
index c4772c36c..92f4021d7 100644
--- a/ui/core/view.d.ts
+++ b/ui/core/view.d.ts
@@ -387,7 +387,7 @@ declare module "ui/core/view" {
onUnloaded(): void;
isLoaded: boolean;
- _addView(view: View);
+ _addView(view: View, atIndex?: number);
_propagateInheritableProperties(view: View)
_inheritProperties(parentView: View)
_removeView(view: View);
@@ -407,7 +407,7 @@ declare module "ui/core/view" {
/**
* Performs the core logic of adding a child view to the native visual tree. Returns true if the view's native representation has been successfully added, false otherwise.
*/
- _addViewToNativeVisualTree(view: View): boolean;
+ _addViewToNativeVisualTree(view: View, atIndex?: number): boolean;
_removeViewFromNativeVisualTree(view: View): void;
_eachChildView(callback: (child: View) => boolean);
diff --git a/ui/core/view.ios.ts b/ui/core/view.ios.ts
index b926fc91f..1e1e4127d 100644
--- a/ui/core/view.ios.ts
+++ b/ui/core/view.ios.ts
@@ -4,6 +4,7 @@ import utils = require("utils/utils");
import dependencyObservable = require("ui/core/dependency-observable");
import proxy = require("ui/core/proxy");
import background = require("ui/styling/background");
+import types = require("utils/types");
global.moduleMerge(viewCommon, exports);
@@ -251,11 +252,17 @@ export class CustomLayoutView extends View {
trace.write(this + " :onMeasure: " + utils.layout.getMode(widthMode) + " " + width + ", " + utils.layout.getMode(heightMode) + " " + height, trace.categories.Layout);
}
- public _addViewToNativeVisualTree(child: View): boolean {
+ public _addViewToNativeVisualTree(child: View, atIndex: number): boolean {
super._addViewToNativeVisualTree(child);
if (this._nativeView && child._nativeView) {
- this._nativeView.addSubview(child._nativeView);
+ if (types.isNullOrUndefined(atIndex) || atIndex >= this._nativeView.subviews.count) {
+ this._nativeView.addSubview(child._nativeView);
+ }
+ else {
+ this._nativeView.insertSubviewAtIndex(child._nativeView, atIndex);
+ }
+
return true;
}
diff --git a/ui/layouts/layout-base.d.ts b/ui/layouts/layout-base.d.ts
index 316e54cc2..f36d88968 100644
--- a/ui/layouts/layout-base.d.ts
+++ b/ui/layouts/layout-base.d.ts
@@ -20,12 +20,25 @@
*/
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 view The view to be added to the end of the children array.
+ * @param atIndex The insertion index.
+ */
+ insertChild(child: view.View, atIndex: number);
+
/**
* Removes the specified view from the children array.
* @param view The view to remove from the children array.
diff --git a/ui/layouts/layout-base.ts b/ui/layouts/layout-base.ts
index 108f43c48..66b29d44b 100644
--- a/ui/layouts/layout-base.ts
+++ b/ui/layouts/layout-base.ts
@@ -43,8 +43,8 @@ export class LayoutBase extends view.CustomLayoutView implements definition.Layo
this._subViews.push(child);
}
- public insertChild(atIndex: number, child: view.View) {
- this._addView(child);
+ public insertChild(child: view.View, atIndex: number) {
+ this._addView(child, atIndex);
this._subViews.splice(atIndex, 0, child);
}
diff --git a/ui/styling/style.ts b/ui/styling/style.ts
index 7cf4de96c..afbc73cf1 100644
--- a/ui/styling/style.ts
+++ b/ui/styling/style.ts
@@ -188,6 +188,38 @@ function onBackgroundImagePropertyChanged(data: observable.PropertyChangeData) {
}
}
+function onBackgroundColorPropertyChanged(data: observable.PropertyChangeData) {
+ var style =