Skip to content

Commit

Permalink
feat(view): introduce LayoutChanged event on every View component (#…
Browse files Browse the repository at this point in the history
…5825)

* feat(view): introduce LayoutChanged event

* test(view): add LayoutChanged event tests

* chore(view-android): attach to onLayoutChange only if listener attached

* feat(view-android): override on/off in order to attach and detach from OnLayoutChangeListener
  • Loading branch information
ADjenkov committed May 21, 2018
1 parent f671f77 commit 0fc1547
Show file tree
Hide file tree
Showing 8 changed files with 305 additions and 18 deletions.
3 changes: 3 additions & 0 deletions tests/app/testRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ allTests["FRAME"] = frameTests;
import * as viewTests from "./ui/view/view-tests";
allTests["VIEW"] = viewTests;

import * as viewLayoutChangedEventTests from "./ui/view/view-tests-layout-event";
allTests["VIEW-LAYOUT-EVENT"] = viewLayoutChangedEventTests;

import * as styleTests from "./ui/styling/style-tests";
allTests["STYLE"] = styleTests;

Expand Down
2 changes: 1 addition & 1 deletion tests/app/ui/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function getColor(uiColor: UIColor): Color {
return new Color(alpha, red, green, blue);
}

function clearPage(): void {
export function clearPage(): void {
let newPage = getCurrentPage();
if (!newPage) {
throw new Error("NO CURRENT PAGE!!!!");
Expand Down
210 changes: 210 additions & 0 deletions tests/app/ui/view/view-tests-layout-event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
import * as commonTests from "./view-tests-common";

import { View } from "tns-core-modules/ui/core/view";
import { Button } from "tns-core-modules/ui/button";
import { StackLayout } from "tns-core-modules/ui/layouts/stack-layout/stack-layout";
import * as helper from "../helper";
import * as TKUnit from "../../TKUnit";
import * as utils from "tns-core-modules/utils/utils";

export function test_event_LayoutChanged_GetActualSize() {
const test = function (views: Array<View>) {
let buttonLayoutChanged = false;

views[1].on(View.layoutChangedEvent, (data) => {
buttonLayoutChanged = true;
});

TKUnit.waitUntilReady(() => buttonLayoutChanged);
TKUnit.assert(views[1].getActualSize().height > 0);
TKUnit.assert(views[1].getActualSize().width > 0);
};

helper.do_PageTest_WithStackLayout_AndButton(test);
};

export function test_event_LayoutChanged_Listeners() {
const test = function (views: Array<View>) {
let stackLayoutChanged = false;
let buttonLayoutChanged = false;

views[1].on(View.layoutChangedEvent, (data) => {
buttonLayoutChanged = true;
});

TKUnit.waitUntilReady(() => buttonLayoutChanged);
TKUnit.assertFalse(views[0].hasListeners(View.layoutChangedEvent));
TKUnit.assert(views[1].hasListeners(View.layoutChangedEvent));
};

helper.do_PageTest_WithStackLayout_AndButton(test);
};

export function test_event_LayoutChanged_IsRaised() {
helper.clearPage();
let newPage = helper.getCurrentPage();

let stackLayoutChanged = false;
let buttonLayoutChanged = false;

let stackLayout = new StackLayout();
let button = new Button();

stackLayout.on(View.layoutChangedEvent, (data) => {
stackLayoutChanged = true;
});

button.on(View.layoutChangedEvent, (data) => {
buttonLayoutChanged = true;
});

stackLayout.addChild(button);
newPage.content = stackLayout;

TKUnit.waitUntilReady(() => stackLayoutChanged && buttonLayoutChanged);
TKUnit.assert(stackLayoutChanged);
TKUnit.assert(buttonLayoutChanged);

newPage.content = null;
};

export function test_event_LayoutChanged_IsRaised_StackLayout_ChildAdded() {
helper.clearPage();
let newPage = helper.getCurrentPage();

let stackLayoutChangedCount = 0;
let button1LayoutChangedCount = 0;
let button2LayoutChanged = false;

let stackLayout = new StackLayout();

// StackLayout should not be stretched in order to layout again when new button added.
stackLayout.verticalAlignment = "top";
let button1 = new Button();
let button2 = new Button();

stackLayout.on(View.layoutChangedEvent, (data) => {
stackLayoutChangedCount++;
});

button1.on(View.layoutChangedEvent, (data) => {
button1LayoutChangedCount++;
});

button2.on(View.layoutChangedEvent, (data) => {
button2LayoutChanged = true;
});

stackLayout.addChild(button1);
newPage.content = stackLayout;

TKUnit.waitUntilReady(() => stackLayout.isLoaded);
stackLayout.addChild(button2);

TKUnit.waitUntilReady(() => button2LayoutChanged);
TKUnit.assertEqual(stackLayoutChangedCount, 2);
TKUnit.assertEqual(button1LayoutChangedCount, 1);
TKUnit.assert(button2LayoutChanged);

newPage.content = null;
};

export function test_event_LayoutChanged_IsRaised_ChildMarginChanged() {
const test = function (views: Array<View>) {
let stackLayoutChanged = false;
let buttonLayoutChanged = false;

views[1].on(View.layoutChangedEvent, (data) => {
stackLayoutChanged = true;
});

views[2].on(View.layoutChangedEvent, (data) => {
buttonLayoutChanged = true;
});

(<Button>views[2]).marginTop = 50;

TKUnit.waitUntilReady(() => buttonLayoutChanged);

TKUnit.assert(stackLayoutChanged);
TKUnit.assert(buttonLayoutChanged);
};

helper.do_PageTest_WithStackLayout_AndButton(test);
};

export function test_event_LayoutChanged_IsRaised_ParentMarginChanged() {
const test = function (views: Array<View>) {
let stackLayoutChanged = false;
let buttonLayoutChanged = false;

views[1].on(View.layoutChangedEvent, (data) => {
stackLayoutChanged = true;
});

views[2].on(View.layoutChangedEvent, (data) => {
buttonLayoutChanged = true;
});

(<Button>views[2]).marginTop = 50;

TKUnit.waitUntilReady(() => buttonLayoutChanged);

TKUnit.assert(stackLayoutChanged);
TKUnit.assert(buttonLayoutChanged);
};

helper.do_PageTest_WithStackLayout_AndButton(test);
};

export function test_event_LayoutChanged_IsNotRaised_TransformChanged() {
const test = function (views: Array<View>) {
let stackLayoutChangedCount = 0;
let buttonLayoutChangedCount = 0;
const button = <Button>views[2];

views[1].on(View.layoutChangedEvent, (data) => {
stackLayoutChangedCount++;
});

button.on(View.layoutChangedEvent, (data) => {
buttonLayoutChangedCount++;
});

button.translateX += 50;
button.translateY += 50;
button.rotate += 50;
button.height = 200;

TKUnit.waitUntilReady(() => button.height === 200);

TKUnit.assertEqual(stackLayoutChangedCount, 1);
TKUnit.assertEqual(buttonLayoutChangedCount, 1);
};

helper.do_PageTest_WithStackLayout_AndButton(test);
};

export function test_event_LayoutChanged_IsRaised_StackLayout_SizeChanged() {
const test = function (views: Array<View>) {
let stackLayoutChanged = false;
let buttonLayoutChanged = false;

views[1].on(View.layoutChangedEvent, (data) => {
stackLayoutChanged = true;
});

views[2].on(View.layoutChangedEvent, (data) => {
buttonLayoutChanged = true;
});

(<StackLayout>views[1]).height = 100;

TKUnit.waitUntilReady(() => buttonLayoutChanged);

TKUnit.assert(stackLayoutChanged);
TKUnit.assert(buttonLayoutChanged);
};

helper.do_PageTest_WithStackLayout_AndButton(test);
};
33 changes: 17 additions & 16 deletions tests/app/ui/view/view-tests.ios.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import * as commonTests from "./view-tests-common";
import * as view from "tns-core-modules/ui/core/view";
import * as grid from "tns-core-modules/ui/layouts/grid-layout";
import * as color from "tns-core-modules/color";

import { View } from "tns-core-modules/ui/core/view";
import { Button } from "tns-core-modules/ui/button";
import { GridLayout } from "tns-core-modules/ui/layouts/grid-layout";
import { Color } from "tns-core-modules/color";
import * as helper from "../helper";
import * as TKUnit from "../../TKUnit";
import * as button from "tns-core-modules/ui/button";
import * as utils from "tns-core-modules/utils/utils";

global.moduleMerge(commonTests, exports);

class MyGrid extends grid.GridLayout {
class MyGrid extends GridLayout {
public backgroundDrawCount: number = 0;

_redrawNativeBackground(background: any) {
Expand All @@ -18,33 +19,33 @@ class MyGrid extends grid.GridLayout {
}
}

export function getUniformNativeBorderWidth(v: view.View): number {
export function getUniformNativeBorderWidth(v: View): number {
return utils.layout.toDevicePixels((<UIView>v.ios).layer.borderWidth);
}

export function checkUniformNativeBorderColor(v: view.View): boolean {
if (v.borderColor instanceof color.Color) {
return (<UIView>v.ios).layer.borderColor === (<color.Color>v.borderColor).ios.CGColor;
export function checkUniformNativeBorderColor(v: View): boolean {
if (v.borderColor instanceof Color) {
return (<UIView>v.ios).layer.borderColor === (<Color>v.borderColor).ios.CGColor;
}

return undefined;
}

export function getUniformNativeCornerRadius(v: view.View): number {
export function getUniformNativeCornerRadius(v: View): number {
return utils.layout.toDevicePixels((<UIView>v.ios).layer.cornerRadius);
}

export function checkNativeBackgroundColor(v: view.View): boolean {
export function checkNativeBackgroundColor(v: View): boolean {
if (v.ios instanceof UILabel) {
var cgColor1 = (<UILabel>v.ios).layer.backgroundColor;
var cgColor2 = (<UIColor>(<color.Color>v.backgroundColor).ios).CGColor;
var cgColor2 = (<UIColor>(<Color>v.backgroundColor).ios).CGColor;
return v.backgroundColor && !!CGColorEqualToColor(cgColor1, cgColor2);
}

return v.backgroundColor && (<UIView>v.ios).backgroundColor.isEqual((<color.Color>v.backgroundColor).ios);
return v.backgroundColor && (<UIView>v.ios).backgroundColor.isEqual((<Color>v.backgroundColor).ios);
}

export function checkNativeBackgroundImage(v: view.View): boolean {
export function checkNativeBackgroundImage(v: View): boolean {
return (<UIView>v.ios).backgroundColor !== undefined;
}

Expand All @@ -53,7 +54,7 @@ export function testBackgroundInternalChangedOnceOnResize() {
let root = helper.getCurrentPage();
let layout = new MyGrid();
layout.className = "myClass";
layout.backgroundColor = new color.Color(255, 255, 0, 0);
layout.backgroundColor = new Color(255, 255, 0, 0);

root.css = ".myClass { background-image: url('~/logo.png') }";
root.content = layout;
Expand Down Expand Up @@ -82,7 +83,7 @@ export function testBackgroundInternalChangedOnceOnResize() {
}

export function test_automation_text_set_to_native() {
var newButton = new button.Button();
var newButton = new Button();
newButton.automationText = "Button1";
helper.getCurrentPage().content = newButton;
TKUnit.assertEqual((<UIView>newButton.ios).accessibilityIdentifier, "Button1", "accessibilityIdentifier not set to native view.");
Expand Down
9 changes: 9 additions & 0 deletions tns-core-modules/ui/core/view/view-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export function PseudoClassHandler(...pseudoClasses: string[]): MethodDecorator
export const _rootModalViews = new Array<ViewBase>();

export abstract class ViewCommon extends ViewBase implements ViewDefinition {
public static layoutChangedEvent = "layoutChanged";
public static shownModallyEvent = "shownModally";
public static showingModallyEvent = "showingModally";

Expand Down Expand Up @@ -277,6 +278,14 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
//
}

protected _raiseLayoutChangedEvent() {
const args: EventData = {
eventName: ViewCommon.layoutChangedEvent,
object: this
};
this.notify(args);
}

protected _raiseShownModallyEvent() {
const args: ShownModallyData = {
eventName: ViewCommon.shownModallyEvent,
Expand Down

0 comments on commit 0fc1547

Please sign in to comment.