From b65e6f6fda62785225ba8351facc6737b072f6c1 Mon Sep 17 00:00:00 2001 From: Panayot Cankov Date: Wed, 8 Jun 2016 13:57:49 +0300 Subject: [PATCH] Layout will not requestLayout when its text is changed if it has fixed size --- tests/app/ui/label/label-tests.ts | 78 ++++++++++++++++++- tns-core-modules/ui/label/label.ios.ts | 22 ++++++ .../ui/text-base/text-base-common.ts | 6 +- tns-core-modules/ui/text-base/text-base.d.ts | 5 ++ .../ui/text-base/text-base.ios.ts | 1 + 5 files changed, 110 insertions(+), 2 deletions(-) diff --git a/tests/app/ui/label/label-tests.ts b/tests/app/ui/label/label-tests.ts index 95e2a5a9a..000e5ed5a 100644 --- a/tests/app/ui/label/label-tests.ts +++ b/tests/app/ui/label/label-tests.ts @@ -1,4 +1,4 @@ -import TKUnit = require("../../TKUnit"); +import * as TKUnit from "../../TKUnit"; import testModule = require("../../ui-test"); import styling = require("ui/styling"); @@ -17,6 +17,13 @@ import labelTestsNative = require("./label-tests-native"); import fs = require("file-system"); 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 { public create(): LabelModule.Label { @@ -524,8 +531,77 @@ export class LabelTest extends testModule.UITest { page.addCss("label { < !--Test wrong comment-- > background-color: red; }"); 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 { return new LabelTest(); } + diff --git a/tns-core-modules/ui/label/label.ios.ts b/tns-core-modules/ui/label/label.ios.ts index a1afc6747..8e5fd2820 100644 --- a/tns-core-modules/ui/label/label.ios.ts +++ b/tns-core-modules/ui/label/label.ios.ts @@ -57,8 +57,16 @@ class UILabelImpl extends UILabel { } } +enum FixedSize { + NONE = 0, + WIDTH = 1, + HEIGHT = 2, + BOTH = 3 +} + export class Label extends common.Label { private _ios: UILabel; + private _fixedSize: FixedSize; constructor() { super(); @@ -81,6 +89,17 @@ export class Label extends common.Label { this.style._updateTextDecoration(); 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 { var nativeView = this._nativeView; @@ -99,6 +118,9 @@ export class Label extends common.Label { 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 labelWidth = nativeSize.width; diff --git a/tns-core-modules/ui/text-base/text-base-common.ts b/tns-core-modules/ui/text-base/text-base-common.ts index 70e1feff4..bda251b87 100644 --- a/tns-core-modules/ui/text-base/text-base-common.ts +++ b/tns-core-modules/ui/text-base/text-base-common.ts @@ -17,7 +17,7 @@ function ensureWeakEvents() { var textProperty = new dependencyObservable.Property( "text", "TextBase", - new proxy.PropertyMetadata("", dependencyObservable.PropertyMetadataSettings.AffectsLayout) + new proxy.PropertyMetadata("", dependencyObservable.PropertyMetadataSettings.None) ); 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 { formattedString.FormattedString.addFormattedStringToView(this, name, value); } + + _requestLayoutOnTextChanged(): void { + this.requestLayout(); + } } tbs.TextBaseStyler.registerHandlers() diff --git a/tns-core-modules/ui/text-base/text-base.d.ts b/tns-core-modules/ui/text-base/text-base.d.ts index c5bdf6fb9..eb335a929 100644 --- a/tns-core-modules/ui/text-base/text-base.d.ts +++ b/tns-core-modules/ui/text-base/text-base.d.ts @@ -49,6 +49,11 @@ //@private _onTextPropertyChanged(data: dependencyObservable.PropertyChangeData): void; _setFormattedTextPropertyToNative(value: any): void; + /** + * @private + * Called when the text property is changed to request layout. + */ + _requestLayoutOnTextChanged(): void; //@endprivate } } \ No newline at end of file diff --git a/tns-core-modules/ui/text-base/text-base.ios.ts b/tns-core-modules/ui/text-base/text-base.ios.ts index 09750986e..f7c8a395d 100644 --- a/tns-core-modules/ui/text-base/text-base.ios.ts +++ b/tns-core-modules/ui/text-base/text-base.ios.ts @@ -8,6 +8,7 @@ export class TextBase extends common.TextBase { this.ios.text = newValue; this.style._updateTextDecoration(); this.style._updateTextTransform(); + this._requestLayoutOnTextChanged(); } public _setFormattedTextPropertyToNative(value) {