Skip to content

Commit 298f263

Browse files
committed
Merge pull request NativeScript#2269 from NativeScript/cankov/label-smart-layout-invalidation
Layout will not requestLayout when its text is changed if it has fixed size
2 parents b47e8f1 + b65e6f6 commit 298f263

File tree

5 files changed

+110
-2
lines changed

5 files changed

+110
-2
lines changed

tests/app/ui/label/label-tests.ts

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import TKUnit = require("../../TKUnit");
1+
import * as TKUnit from "../../TKUnit";
22
import testModule = require("../../ui-test");
33
import styling = require("ui/styling");
44

@@ -17,6 +17,13 @@ import labelTestsNative = require("./label-tests-native");
1717
import fs = require("file-system");
1818
import background = require("ui/styling/background");
1919

20+
import {StackLayout} from "ui/layouts/stack-layout";
21+
import {GridLayout} from "ui/layouts/grid-layout";
22+
import {isIOS} from "platform";
23+
import {Label} from "ui/label";
24+
import {LayoutBase} from "ui/layouts/layout-base";
25+
import * as helper from "../helper";
26+
2027
export class LabelTest extends testModule.UITest<LabelModule.Label> {
2128

2229
public create(): LabelModule.Label {
@@ -524,8 +531,77 @@ export class LabelTest extends testModule.UITest<LabelModule.Label> {
524531
page.addCss("label { < !--Test wrong comment-- > background-color: red; }");
525532
TKUnit.assertNotEqual(this.errorMessage, undefined);
526533
}
534+
535+
private requestLayoutFixture(expectRequestLayout: boolean, setup: (label: Label) => LayoutBase): void {
536+
if (!isIOS) {
537+
return;
538+
}
539+
540+
let label = new Label();
541+
let host = setup(label);
542+
543+
host.addChild(label);
544+
545+
let mainPage = helper.getCurrentPage();
546+
mainPage.content = host;
547+
TKUnit.waitUntilReady(() => host.isLoaded);
548+
549+
let called = false;
550+
label.requestLayout = () => called = true;
551+
label.text = "Hello World";
552+
553+
if (expectRequestLayout) {
554+
TKUnit.assertTrue(called, "label.requestLayout should be called.");
555+
} else {
556+
TKUnit.assertFalse(called, "image.requestLayout should not be called.");
557+
}
558+
}
559+
560+
public test_SettingTextWhenInFixedSizeGridShouldNotRequestLayout() {
561+
this.requestLayoutFixture(false, () => {
562+
let host = new GridLayout();
563+
host.width = 100;
564+
host.height = 100;
565+
return host;
566+
});
567+
}
568+
569+
public test_SettingTextWhenFixedWidthAndHeightDoesNotRequestLayout() {
570+
this.requestLayoutFixture(false, label => {
571+
let host = new StackLayout();
572+
label.width = 100;
573+
label.height = 100;
574+
return host;
575+
});
576+
};
577+
578+
public test_SettingTextWhenSizedToContentShouldInvalidate() {
579+
this.requestLayoutFixture(true, () => {
580+
let host = new StackLayout();
581+
host.orientation = "horizontal";
582+
return host;
583+
});
584+
};
585+
586+
public test_SettingTextOnSingleLineTextWhenWidthIsSizedToParentAndHeightIsSizedToContentShouldNotRequestLayout() {
587+
this.requestLayoutFixture(false, () => {
588+
let host = new StackLayout();
589+
host.width = 100;
590+
return host;
591+
});
592+
}
593+
594+
public test_SettingTextOnMultilineLineTextWhenWidthIsSizedToParentAndHeightIsSizedToContentShouldRequestLayout() {
595+
this.requestLayoutFixture(true, label => {
596+
label.textWrap = true;
597+
let host = new StackLayout();
598+
host.width = 100;
599+
return host;
600+
});
601+
}
527602
}
528603

529604
export function createTestCase(): LabelTest {
530605
return new LabelTest();
531606
}
607+

tns-core-modules/ui/label/label.ios.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,16 @@ class UILabelImpl extends UILabel {
5757
}
5858
}
5959

60+
enum FixedSize {
61+
NONE = 0,
62+
WIDTH = 1,
63+
HEIGHT = 2,
64+
BOTH = 3
65+
}
66+
6067
export class Label extends common.Label {
6168
private _ios: UILabel;
69+
private _fixedSize: FixedSize;
6270

6371
constructor() {
6472
super();
@@ -81,6 +89,17 @@ export class Label extends common.Label {
8189
this.style._updateTextDecoration();
8290
this.style._updateTextTransform();
8391
}
92+
93+
_requestLayoutOnTextChanged(): void {
94+
if (this._fixedSize === FixedSize.BOTH) {
95+
return;
96+
}
97+
if (this._fixedSize === FixedSize.WIDTH && !this.textWrap) {
98+
// Single line label with fixed width will skip request layout on text change.
99+
return;
100+
}
101+
super._requestLayoutOnTextChanged();
102+
}
84103

85104
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
86105
var nativeView = this._nativeView;
@@ -99,6 +118,9 @@ export class Label extends common.Label {
99118
height = Number.POSITIVE_INFINITY;
100119
}
101120

121+
this._fixedSize = (widthMode === utils.layout.EXACTLY ? FixedSize.WIDTH : FixedSize.NONE)
122+
| (heightMode === utils.layout.EXACTLY ? FixedSize.HEIGHT : FixedSize.NONE);
123+
102124
var nativeSize = nativeView.sizeThatFits(CGSizeMake(width, height));
103125
var labelWidth = nativeSize.width;
104126

tns-core-modules/ui/text-base/text-base-common.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ function ensureWeakEvents() {
1717
var textProperty = new dependencyObservable.Property(
1818
"text",
1919
"TextBase",
20-
new proxy.PropertyMetadata("", dependencyObservable.PropertyMetadataSettings.AffectsLayout)
20+
new proxy.PropertyMetadata("", dependencyObservable.PropertyMetadataSettings.None)
2121
);
2222

2323
var formattedTextProperty = new dependencyObservable.Property(
@@ -127,6 +127,10 @@ export class TextBase extends view.View implements definition.TextBase, formatte
127127
public _addChildFromBuilder(name: string, value: any): void {
128128
formattedString.FormattedString.addFormattedStringToView(this, name, value);
129129
}
130+
131+
_requestLayoutOnTextChanged(): void {
132+
this.requestLayout();
133+
}
130134
}
131135

132136
tbs.TextBaseStyler.registerHandlers()

tns-core-modules/ui/text-base/text-base.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@
4949
//@private
5050
_onTextPropertyChanged(data: dependencyObservable.PropertyChangeData): void;
5151
_setFormattedTextPropertyToNative(value: any): void;
52+
/**
53+
* @private
54+
* Called when the text property is changed to request layout.
55+
*/
56+
_requestLayoutOnTextChanged(): void;
5257
//@endprivate
5358
}
5459
}

tns-core-modules/ui/text-base/text-base.ios.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export class TextBase extends common.TextBase {
88
this.ios.text = newValue;
99
this.style._updateTextDecoration();
1010
this.style._updateTextTransform();
11+
this._requestLayoutOnTextChanged();
1112
}
1213

1314
public _setFormattedTextPropertyToNative(value) {

0 commit comments

Comments
 (0)