Skip to content

Commit a14becd

Browse files
authored
fix(ios): FormattedString and Span a11y font scale (#10281)
1 parent b8a548f commit a14becd

File tree

8 files changed

+142
-46
lines changed

8 files changed

+142
-46
lines changed

apps/automated/src/test-runner.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,9 @@ allTests['LISTVIEW'] = listViewTests;
227227
import * as activityIndicatorTests from './ui/activity-indicator/activity-indicator-tests';
228228
allTests['ACTIVITY-INDICATOR'] = activityIndicatorTests;
229229

230+
import * as textBaseTests from './ui/text-base/text-base-tests';
231+
allTests['TEXT-BASE'] = textBaseTests;
232+
230233
import * as textFieldTests from './ui/text-field/text-field-tests';
231234
allTests['TEXT-FIELD'] = textFieldTests;
232235

apps/automated/src/ui/styling/style-properties-tests.ts

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -580,26 +580,6 @@ export function test_setting_font_properties_sets_native_font() {
580580
test_native_font('italic', 'bold');
581581
}
582582

583-
export function test_native_font_size_with_a11y_font_scale() {
584-
if (isIOS) {
585-
const deviceFontScaleMock = 4.0;
586-
587-
const page = helper.getCurrentPage();
588-
const testView = new Label();
589-
const layout = new StackLayout();
590-
layout.addChild(testView);
591-
592-
page.content = layout;
593-
594-
layout.style.iosAccessibilityAdjustsFontSize = true;
595-
layout.style.fontScaleInternal = deviceFontScaleMock;
596-
597-
const nativeFontSize = testView.nativeTextViewProtected.font.pointSize;
598-
const expectedNativeFontSize = testView.style.fontInternal.fontSize * deviceFontScaleMock;
599-
TKUnit.assertEqual(nativeFontSize, expectedNativeFontSize, 'View font size does not respect a11y font scaling');
600-
}
601-
}
602-
603583
function test_native_font(style: 'normal' | 'italic', weight: '100' | '200' | '300' | 'normal' | '400' | '500' | '600' | 'bold' | '700' | '800' | '900') {
604584
const testView = new Button();
605585

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import * as TKUnit from '../../tk-unit';
2+
import * as helper from '../../ui-helper';
3+
import { FormattedString, isIOS, Label, Span, StackLayout } from '@nativescript/core';
4+
5+
export function test_native_font_size_with_a11y_font_scale() {
6+
if (isIOS) {
7+
const deviceFontScaleMock = 4.0;
8+
9+
const page = helper.getCurrentPage();
10+
const testView = new Label();
11+
const layout = new StackLayout();
12+
layout.addChild(testView);
13+
14+
page.content = layout;
15+
16+
layout.style.iosAccessibilityAdjustsFontSize = true;
17+
layout.style.fontScaleInternal = deviceFontScaleMock;
18+
19+
const nativeFontSize = testView.nativeTextViewProtected.font.pointSize;
20+
const expectedNativeFontSize = testView.style.fontInternal.fontSize * deviceFontScaleMock;
21+
TKUnit.assertEqual(nativeFontSize, expectedNativeFontSize, 'View font size does not respect a11y font scaling');
22+
}
23+
}

packages/core/ui/text-base/formatted-string.d.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Span } from './span';
66
import { ObservableArray } from '../../data/observable-array';
77
import { ViewBase } from '../core/view-base';
88
import { Color } from '../../color';
9-
import { FontStyle, FontWeight } from '../styling/font';
9+
import { FontStyleType, FontWeightType } from '../styling/font';
1010
import { CoreTypes } from '../../core-types';
1111

1212
/**
@@ -36,12 +36,12 @@ export class FormattedString extends ViewBase {
3636
/**
3737
* Gets or sets the font style which will be used for all spans that doesn't have a specific value.
3838
*/
39-
public fontStyle: FontStyle;
39+
public fontStyle: FontStyleType;
4040

4141
/**
4242
* Gets or sets the font weight which will be used for all spans that doesn't have a specific value.
4343
*/
44-
public fontWeight: FontWeight;
44+
public fontWeight: FontWeightType;
4545

4646
/**
4747
* Gets or sets text decorations which will be used for all spans that doesn't have a specific value.
@@ -57,4 +57,19 @@ export class FormattedString extends ViewBase {
5757
* Gets or sets the font background color which will be used for all spans that doesn't have a specific value.
5858
*/
5959
public backgroundColor: Color;
60+
61+
/**
62+
* Defines whether accessibility font scale should affect font size.
63+
*/
64+
iosAccessibilityAdjustsFontSize: boolean;
65+
66+
/**
67+
* Gets or sets the minimum accessibility font scale.
68+
*/
69+
iosAccessibilityMinFontScale: number;
70+
71+
/**
72+
* Gets or sets the maximum accessibility font scale.
73+
*/
74+
iosAccessibilityMaxFontScale: number;
6075
}

packages/core/ui/text-base/formatted-string.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,27 @@ export class FormattedString extends ViewBase implements FormattedStringDefiniti
6666
this.style.backgroundColor = value;
6767
}
6868

69+
get iosAccessibilityAdjustsFontSize(): boolean {
70+
return this.style.iosAccessibilityAdjustsFontSize;
71+
}
72+
set iosAccessibilityAdjustsFontSize(value: boolean) {
73+
this.style.iosAccessibilityAdjustsFontSize = value;
74+
}
75+
76+
get iosAccessibilityMinFontScale(): number {
77+
return this.style.iosAccessibilityMinFontScale;
78+
}
79+
set iosAccessibilityMinFontScale(value: number) {
80+
this.style.iosAccessibilityMinFontScale = value;
81+
}
82+
83+
get iosAccessibilityMaxFontScale(): number {
84+
return this.style.iosAccessibilityMaxFontScale;
85+
}
86+
set iosAccessibilityMaxFontScale(value: number) {
87+
this.style.iosAccessibilityMaxFontScale = value;
88+
}
89+
6990
get spans(): ObservableArray<Span> {
7091
if (!this._spans) {
7192
this._spans = new ObservableArray<Span>();
@@ -135,6 +156,12 @@ export class FormattedString extends ViewBase implements FormattedStringDefiniti
135156
style.on('textDecorationChange', this.onPropertyChange, this);
136157
style.on('colorChange', this.onPropertyChange, this);
137158
style.on('backgroundColorChange', this.onPropertyChange, this);
159+
160+
// These handlers will trigger font scale update
161+
style.on('iosAccessibilityAdjustsFontSizeChange', this.onPropertyChange, this);
162+
style.on('iosAccessibilityMinFontScaleChange', this.onPropertyChange, this);
163+
style.on('iosAccessibilityMaxFontScaleChange', this.onPropertyChange, this);
164+
style.on('fontScaleInternalChange', this.onPropertyChange, this);
138165
}
139166

140167
private removePropertyChangeHandler(span: Span) {
@@ -147,6 +174,11 @@ export class FormattedString extends ViewBase implements FormattedStringDefiniti
147174
style.off('textDecorationChange', this.onPropertyChange, this);
148175
style.off('colorChange', this.onPropertyChange, this);
149176
style.off('backgroundColorChange', this.onPropertyChange, this);
177+
178+
style.off('iosAccessibilityAdjustsFontSizeChange', this.onPropertyChange, this);
179+
style.off('iosAccessibilityMinFontScaleChange', this.onPropertyChange, this);
180+
style.off('iosAccessibilityMaxFontScaleChange', this.onPropertyChange, this);
181+
style.off('fontScaleInternalChange', this.onPropertyChange, this);
150182
}
151183

152184
private onPropertyChange(data: PropertyChangeData) {

packages/core/ui/text-base/index.ios.ts

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -194,28 +194,17 @@ export class TextBase extends TextBaseCommon {
194194

195195
[fontScaleInternalProperty.setNative](value: number) {
196196
const nativeView = this.nativeTextViewProtected instanceof UIButton ? this.nativeTextViewProtected.titleLabel : this.nativeTextViewProtected;
197-
const currentFont = this.style.fontInternal || Font.default.withFontSize(nativeView.font.pointSize);
198-
199-
let finalValue;
200-
if (this.iosAccessibilityAdjustsFontSize) {
201-
finalValue = value;
202-
203-
if (this.iosAccessibilityMinFontScale && this.iosAccessibilityMinFontScale > value) {
204-
finalValue = this.iosAccessibilityMinFontScale;
205-
}
206-
if (this.iosAccessibilityMaxFontScale && this.iosAccessibilityMaxFontScale < value) {
207-
finalValue = this.iosAccessibilityMaxFontScale;
208-
}
209-
} else {
210-
finalValue = 1.0;
211-
}
212-
213-
const newFont = currentFont.withFontScale(finalValue);
214-
this.style.fontInternal = newFont;
197+
const font = this.style.fontInternal || Font.default.withFontSize(nativeView.font.pointSize);
198+
const finalValue = adjustMinMaxFontScale(value, this);
215199

216200
// Request layout on font scale as it's not done automatically
217-
if (currentFont.fontScale !== finalValue) {
201+
if (font.fontScale !== finalValue) {
202+
this.style.fontInternal = font.withFontScale(finalValue);
218203
this.requestLayout();
204+
} else {
205+
if (!this.style.fontInternal) {
206+
this.style.fontInternal = font;
207+
}
219208
}
220209
}
221210

@@ -360,7 +349,8 @@ export class TextBase extends TextBaseCommon {
360349
}
361350

362351
createMutableStringDetails(span: Span, text: string, index?: number): any {
363-
const font = new Font(span.style.fontFamily, span.style.fontSize, span.style.fontStyle, span.style.fontWeight);
352+
const fontScale = adjustMinMaxFontScale(span.style.fontScaleInternal, span);
353+
const font = new Font(span.style.fontFamily, span.style.fontSize, span.style.fontStyle, span.style.fontWeight, fontScale);
364354
const iosFont = font.getUIFont(this.nativeTextViewProtected.font);
365355

366356
const backgroundColor = <Color>(span.style.backgroundColor || (<FormattedString>span.parent).backgroundColor || (<TextBase>span.parent.parent).backgroundColor);
@@ -485,3 +475,20 @@ function isStringTappable(formattedString: FormattedString) {
485475

486476
return false;
487477
}
478+
479+
function adjustMinMaxFontScale(value: number, view: TextBase | Span) {
480+
let finalValue;
481+
if (view.iosAccessibilityAdjustsFontSize) {
482+
finalValue = value;
483+
484+
if (view.iosAccessibilityMinFontScale && view.iosAccessibilityMinFontScale > value) {
485+
finalValue = view.iosAccessibilityMinFontScale;
486+
}
487+
if (view.iosAccessibilityMaxFontScale && view.iosAccessibilityMaxFontScale < value) {
488+
finalValue = view.iosAccessibilityMaxFontScale;
489+
}
490+
} else {
491+
finalValue = 1.0;
492+
}
493+
return finalValue;
494+
}

packages/core/ui/text-base/span.d.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Color } from '../../color';
22
import { ViewBase } from '../core/view-base';
3-
import { FontStyle, FontWeight } from '../styling/font';
3+
import { FontStyleType, FontWeightType } from '../styling/font';
44
import { CoreTypes } from '../../core-types';
55

66
/**
@@ -20,12 +20,12 @@ export class Span extends ViewBase {
2020
/**
2121
* Gets or sets the font style of the span.
2222
*/
23-
public fontStyle: FontStyle;
23+
public fontStyle: FontStyleType;
2424

2525
/**
2626
* Gets or sets the font weight of the span.
2727
*/
28-
public fontWeight: FontWeight;
28+
public fontWeight: FontWeightType;
2929

3030
/**
3131
* Gets or sets text decorations for the span.
@@ -42,6 +42,21 @@ export class Span extends ViewBase {
4242
*/
4343
public backgroundColor: Color;
4444

45+
/**
46+
* Defines whether accessibility font scale should affect font size.
47+
*/
48+
iosAccessibilityAdjustsFontSize: boolean;
49+
50+
/**
51+
* Gets or sets the minimum accessibility font scale.
52+
*/
53+
iosAccessibilityMinFontScale: number;
54+
55+
/**
56+
* Gets or sets the maximum accessibility font scale.
57+
*/
58+
iosAccessibilityMaxFontScale: number;
59+
4560
/**
4661
* Gets or sets the text for the span.
4762
*/

packages/core/ui/text-base/span.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,27 @@ export class Span extends ViewBase implements SpanDefinition {
6262
this.style.backgroundColor = value;
6363
}
6464

65+
get iosAccessibilityAdjustsFontSize(): boolean {
66+
return this.style.iosAccessibilityAdjustsFontSize;
67+
}
68+
set iosAccessibilityAdjustsFontSize(value: boolean) {
69+
this.style.iosAccessibilityAdjustsFontSize = value;
70+
}
71+
72+
get iosAccessibilityMinFontScale(): number {
73+
return this.style.iosAccessibilityMinFontScale;
74+
}
75+
set iosAccessibilityMinFontScale(value: number) {
76+
this.style.iosAccessibilityMinFontScale = value;
77+
}
78+
79+
get iosAccessibilityMaxFontScale(): number {
80+
return this.style.iosAccessibilityMaxFontScale;
81+
}
82+
set iosAccessibilityMaxFontScale(value: number) {
83+
this.style.iosAccessibilityMaxFontScale = value;
84+
}
85+
6586
get text(): string {
6687
return this._text;
6788
}

0 commit comments

Comments
 (0)