Merge pull request #2269 from NativeScript/cankov/label-smart-layout-invalidation

Layout will not requestLayout when its text is changed if it has fixed size
This commit is contained in:
Panayot Cankov
2016-06-08 15:39:08 +03:00
5 changed files with 110 additions and 2 deletions

View File

@ -1,4 +1,4 @@
import TKUnit = require("../../TKUnit"); import * as TKUnit from "../../TKUnit";
import testModule = require("../../ui-test"); import testModule = require("../../ui-test");
import styling = require("ui/styling"); import styling = require("ui/styling");
@ -17,6 +17,13 @@ import labelTestsNative = require("./label-tests-native");
import fs = require("file-system"); import fs = require("file-system");
import background = require("ui/styling/background"); import background = require("ui/styling/background");
import {StackLayout} from "ui/layouts/stack-layout";
import {GridLayout} from "ui/layouts/grid-layout";
import {isIOS} from "platform";
import {Label} from "ui/label";
import {LayoutBase} from "ui/layouts/layout-base";
import * as helper from "../helper";
export class LabelTest extends testModule.UITest<LabelModule.Label> { export class LabelTest extends testModule.UITest<LabelModule.Label> {
public create(): LabelModule.Label { public create(): LabelModule.Label {
@ -524,8 +531,77 @@ export class LabelTest extends testModule.UITest<LabelModule.Label> {
page.addCss("label { < !--Test wrong comment-- > background-color: red; }"); page.addCss("label { < !--Test wrong comment-- > background-color: red; }");
TKUnit.assertNotEqual(this.errorMessage, undefined); TKUnit.assertNotEqual(this.errorMessage, undefined);
} }
private requestLayoutFixture(expectRequestLayout: boolean, setup: (label: Label) => LayoutBase): void {
if (!isIOS) {
return;
}
let label = new Label();
let host = setup(label);
host.addChild(label);
let mainPage = helper.getCurrentPage();
mainPage.content = host;
TKUnit.waitUntilReady(() => host.isLoaded);
let called = false;
label.requestLayout = () => called = true;
label.text = "Hello World";
if (expectRequestLayout) {
TKUnit.assertTrue(called, "label.requestLayout should be called.");
} else {
TKUnit.assertFalse(called, "image.requestLayout should not be called.");
}
}
public test_SettingTextWhenInFixedSizeGridShouldNotRequestLayout() {
this.requestLayoutFixture(false, () => {
let host = new GridLayout();
host.width = 100;
host.height = 100;
return host;
});
}
public test_SettingTextWhenFixedWidthAndHeightDoesNotRequestLayout() {
this.requestLayoutFixture(false, label => {
let host = new StackLayout();
label.width = 100;
label.height = 100;
return host;
});
};
public test_SettingTextWhenSizedToContentShouldInvalidate() {
this.requestLayoutFixture(true, () => {
let host = new StackLayout();
host.orientation = "horizontal";
return host;
});
};
public test_SettingTextOnSingleLineTextWhenWidthIsSizedToParentAndHeightIsSizedToContentShouldNotRequestLayout() {
this.requestLayoutFixture(false, () => {
let host = new StackLayout();
host.width = 100;
return host;
});
}
public test_SettingTextOnMultilineLineTextWhenWidthIsSizedToParentAndHeightIsSizedToContentShouldRequestLayout() {
this.requestLayoutFixture(true, label => {
label.textWrap = true;
let host = new StackLayout();
host.width = 100;
return host;
});
}
} }
export function createTestCase(): LabelTest { export function createTestCase(): LabelTest {
return new LabelTest(); return new LabelTest();
} }

View File

@ -57,8 +57,16 @@ class UILabelImpl extends UILabel {
} }
} }
enum FixedSize {
NONE = 0,
WIDTH = 1,
HEIGHT = 2,
BOTH = 3
}
export class Label extends common.Label { export class Label extends common.Label {
private _ios: UILabel; private _ios: UILabel;
private _fixedSize: FixedSize;
constructor() { constructor() {
super(); super();
@ -82,6 +90,17 @@ export class Label extends common.Label {
this.style._updateTextTransform(); this.style._updateTextTransform();
} }
_requestLayoutOnTextChanged(): void {
if (this._fixedSize === FixedSize.BOTH) {
return;
}
if (this._fixedSize === FixedSize.WIDTH && !this.textWrap) {
// Single line label with fixed width will skip request layout on text change.
return;
}
super._requestLayoutOnTextChanged();
}
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void { public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
var nativeView = this._nativeView; var nativeView = this._nativeView;
if (nativeView) { if (nativeView) {
@ -99,6 +118,9 @@ export class Label extends common.Label {
height = Number.POSITIVE_INFINITY; height = Number.POSITIVE_INFINITY;
} }
this._fixedSize = (widthMode === utils.layout.EXACTLY ? FixedSize.WIDTH : FixedSize.NONE)
| (heightMode === utils.layout.EXACTLY ? FixedSize.HEIGHT : FixedSize.NONE);
var nativeSize = nativeView.sizeThatFits(CGSizeMake(width, height)); var nativeSize = nativeView.sizeThatFits(CGSizeMake(width, height));
var labelWidth = nativeSize.width; var labelWidth = nativeSize.width;

View File

@ -17,7 +17,7 @@ function ensureWeakEvents() {
var textProperty = new dependencyObservable.Property( var textProperty = new dependencyObservable.Property(
"text", "text",
"TextBase", "TextBase",
new proxy.PropertyMetadata("", dependencyObservable.PropertyMetadataSettings.AffectsLayout) new proxy.PropertyMetadata("", dependencyObservable.PropertyMetadataSettings.None)
); );
var formattedTextProperty = new dependencyObservable.Property( var formattedTextProperty = new dependencyObservable.Property(
@ -127,6 +127,10 @@ export class TextBase extends view.View implements definition.TextBase, formatte
public _addChildFromBuilder(name: string, value: any): void { public _addChildFromBuilder(name: string, value: any): void {
formattedString.FormattedString.addFormattedStringToView(this, name, value); formattedString.FormattedString.addFormattedStringToView(this, name, value);
} }
_requestLayoutOnTextChanged(): void {
this.requestLayout();
}
} }
tbs.TextBaseStyler.registerHandlers() tbs.TextBaseStyler.registerHandlers()

View File

@ -49,6 +49,11 @@
//@private //@private
_onTextPropertyChanged(data: dependencyObservable.PropertyChangeData): void; _onTextPropertyChanged(data: dependencyObservable.PropertyChangeData): void;
_setFormattedTextPropertyToNative(value: any): void; _setFormattedTextPropertyToNative(value: any): void;
/**
* @private
* Called when the text property is changed to request layout.
*/
_requestLayoutOnTextChanged(): void;
//@endprivate //@endprivate
} }
} }

View File

@ -8,6 +8,7 @@ export class TextBase extends common.TextBase {
this.ios.text = newValue; this.ios.text = newValue;
this.style._updateTextDecoration(); this.style._updateTextDecoration();
this.style._updateTextTransform(); this.style._updateTextTransform();
this._requestLayoutOnTextChanged();
} }
public _setFormattedTextPropertyToNative(value) { public _setFormattedTextPropertyToNative(value) {