Skip to content

Commit 481043f

Browse files
authored
fix: label text wrapping inside flexbox layout (#5781)
1 parent 7edf561 commit 481043f

5 files changed

Lines changed: 109 additions & 2 deletions

File tree

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
image {
2+
width: 40;
3+
height: 40;
4+
flex-grow: 0;
5+
flex-shrink: 0;
6+
}
7+
8+
Label {
9+
border-width: 1;
10+
border-color: black;
11+
padding: 0;
12+
flex-grow: 1;
13+
flex-shrink: 1;
14+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<Page xmlns="http://schemas.nativescript.org/tns.xsd" class="page">
2+
3+
<StackLayout width="200" class="p-20">
4+
5+
<!-- Android -->
6+
<FlexboxLayout>
7+
<Label textWrap="true" text="a b c d e f g h i j k l m n o p q r s t" />
8+
</FlexboxLayout>
9+
10+
<FlexboxLayout>
11+
<Image src="https://placehold.it/40x40" />
12+
<Label textWrap="true" text="a b c d e f g h i j k l m n o p" />
13+
</FlexboxLayout>
14+
15+
<FlexboxLayout flexWrap="wrap">
16+
<Label textWrap="true" text="a b c d e f g h i j k l m n o p q r s t" />
17+
<Label textWrap="true" text="a b c d e f g h i j k l m n o p q r s t" />
18+
</FlexboxLayout>
19+
20+
21+
<!-- iOS -->
22+
<FlexboxLayout>
23+
<Label textWrap="true" text="a b c d e f g h i j k l m n o p" />
24+
</FlexboxLayout>
25+
26+
<FlexboxLayout>
27+
<Label textWrap="true" text="a b c d e f g h i j k l m n o p q" />
28+
</FlexboxLayout>
29+
30+
<FlexboxLayout>
31+
<Image src="https://placehold.it/40x40" />
32+
<Label textWrap="true" text="a b c d e f g h i j k l m" />
33+
</FlexboxLayout>
34+
35+
<FlexboxLayout>
36+
<Image src="https://placehold.it/40x40" />
37+
<Label textWrap="true" text="a b c d e f g h i j k l m n" />
38+
</FlexboxLayout>
39+
40+
<FlexboxLayout flexWrap="wrap">
41+
<Label textWrap="true" text="a b c d e f g h i j k l m n o p" />
42+
<Label textWrap="true" text="a b c d e f g h i j k l m n o p q" />
43+
</FlexboxLayout>
44+
45+
46+
<!-- Common -->
47+
<FlexboxLayout alignItems="flex-start">
48+
<Label textWrap="true" text="a b" style="flex-shrink:0;" />
49+
<Label textWrap="true" text="a b c d e f g h i" />
50+
<Label textWrap="true" text="a b c d e f g h i j" />
51+
<Label textWrap="true" text="a b c d e f g h i j k" />
52+
</FlexboxLayout>
53+
54+
</StackLayout>
55+
</Page>

apps/app/ui-tests-app/flexbox/flexbox-main-page.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export function loadExamples() {
1717
examples.set("flexrepeat", "flexbox/flexbox-repeater");
1818
examples.set("flex-perf", "flexbox/flexbox-perf-comparison");
1919
examples.set("flexbox-4143", "flexbox/flexbox-4143");
20+
examples.set("flexbox-4834", "flexbox/flexbox-4834");
2021

2122
return examples;
2223
}

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,11 @@ export class Label extends TextBase implements LabelDefinition {
6868
this._fixedSize = (widthMode === layout.EXACTLY ? FixedSize.WIDTH : FixedSize.NONE)
6969
| (heightMode === layout.EXACTLY ? FixedSize.HEIGHT : FixedSize.NONE);
7070

71-
const nativeSize = layout.measureNativeView(nativeView, width, widthMode, height, heightMode);
71+
// NOTE: utils.measureNativeView(...) relies on UIView.sizeThatFits(...) that
72+
// seems to have various issues when laying out UILabel instances.
73+
// We use custom measure logic here that relies on overriden
74+
// UILabel.textRectForBounds:limitedToNumberOfLines: in TNSLabel widget.
75+
const nativeSize = this._measureNativeView(width, widthMode, height, heightMode);
7276
let labelWidth = nativeSize.width;
7377

7478
if (this.textWrap && widthMode === layout.AT_MOST) {
@@ -85,6 +89,22 @@ export class Label extends TextBase implements LabelDefinition {
8589
}
8690
}
8791

92+
private _measureNativeView(width: number, widthMode: number, height: number, heightMode: number): { width: number, height: number } {
93+
const view = <UILabel>this.nativeViewProtected;
94+
95+
const nativeSize = view.textRectForBoundsLimitedToNumberOfLines(
96+
CGRectMake(
97+
0,
98+
0,
99+
widthMode === 0 /* layout.UNSPECIFIED */ ? Number.POSITIVE_INFINITY : layout.toDeviceIndependentPixels(width),
100+
heightMode === 0 /* layout.UNSPECIFIED */ ? Number.POSITIVE_INFINITY : layout.toDeviceIndependentPixels(height)
101+
), 0).size;
102+
103+
nativeSize.width = layout.round(layout.toDevicePixels(nativeSize.width));
104+
nativeSize.height = layout.round(layout.toDevicePixels(nativeSize.height));
105+
return nativeSize;
106+
}
107+
88108
[whiteSpaceProperty.setNative](value: WhiteSpace) {
89109
const nativeView = this.nativeViewProtected;
90110
switch (value) {

tns-core-modules/ui/layouts/flexbox-layout/flexbox-layout.ios.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,8 +595,25 @@ export class FlexboxLayout extends FlexboxLayoutBase {
595595
} else {
596596
accumulatedRoundError = rawCalculatedWidth - roundedCalculatedWidth;
597597
}
598-
child.measure(makeMeasureSpec(roundedCalculatedWidth, EXACTLY), makeMeasureSpec(child.getMeasuredHeight(), EXACTLY));
598+
599+
const childWidthMeasureSpec = makeMeasureSpec(roundedCalculatedWidth, EXACTLY);
600+
601+
// NOTE: for controls that support internal content wrapping (e.g. UILabel) reducing the width
602+
// might result in increased height e.g. text that could be shown on one line for larger
603+
// width needs to be wrapped in two when width is reduced.
604+
// As a result we cannot unconditionally measure with EXACTLY the current measured height
605+
const childHeightMeasureSpec = FlexboxLayout.getChildMeasureSpec(this._currentHeightMeasureSpec,
606+
lp.effectivePaddingTop + lp.effectivePaddingBottom + lp.effectiveMarginTop
607+
+ lp.effectiveMarginBottom, lp.effectiveHeight < 0 ? WRAP_CONTENT : lp.effectiveHeight);
608+
609+
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
599610
child.effectiveMinWidth = minWidth;
611+
612+
// make sure crossSize is up-to-date as child calculated height might have increased
613+
flexLine._crossSize = Math.max(
614+
flexLine._crossSize,
615+
child.getMeasuredHeight() + lp.effectiveMarginTop + lp.effectiveMarginBottom
616+
);
600617
}
601618
flexLine._mainSize += child.getMeasuredWidth() + lp.effectiveMarginLeft + lp.effectiveMarginRight;
602619
} else {

0 commit comments

Comments
 (0)