fix(ios): FormattedString and Span a11y font scale (#10281)

This commit is contained in:
Dimitris-Rafail Katsampas
2023-05-01 22:29:36 +03:00
committed by GitHub
parent b8a548f009
commit a14becdc6a
8 changed files with 142 additions and 46 deletions

View File

@ -227,6 +227,9 @@ allTests['LISTVIEW'] = listViewTests;
import * as activityIndicatorTests from './ui/activity-indicator/activity-indicator-tests';
allTests['ACTIVITY-INDICATOR'] = activityIndicatorTests;
import * as textBaseTests from './ui/text-base/text-base-tests';
allTests['TEXT-BASE'] = textBaseTests;
import * as textFieldTests from './ui/text-field/text-field-tests';
allTests['TEXT-FIELD'] = textFieldTests;

View File

@ -580,26 +580,6 @@ export function test_setting_font_properties_sets_native_font() {
test_native_font('italic', 'bold');
}
export function test_native_font_size_with_a11y_font_scale() {
if (isIOS) {
const deviceFontScaleMock = 4.0;
const page = helper.getCurrentPage();
const testView = new Label();
const layout = new StackLayout();
layout.addChild(testView);
page.content = layout;
layout.style.iosAccessibilityAdjustsFontSize = true;
layout.style.fontScaleInternal = deviceFontScaleMock;
const nativeFontSize = testView.nativeTextViewProtected.font.pointSize;
const expectedNativeFontSize = testView.style.fontInternal.fontSize * deviceFontScaleMock;
TKUnit.assertEqual(nativeFontSize, expectedNativeFontSize, 'View font size does not respect a11y font scaling');
}
}
function test_native_font(style: 'normal' | 'italic', weight: '100' | '200' | '300' | 'normal' | '400' | '500' | '600' | 'bold' | '700' | '800' | '900') {
const testView = new Button();

View File

@ -0,0 +1,23 @@
import * as TKUnit from '../../tk-unit';
import * as helper from '../../ui-helper';
import { FormattedString, isIOS, Label, Span, StackLayout } from '@nativescript/core';
export function test_native_font_size_with_a11y_font_scale() {
if (isIOS) {
const deviceFontScaleMock = 4.0;
const page = helper.getCurrentPage();
const testView = new Label();
const layout = new StackLayout();
layout.addChild(testView);
page.content = layout;
layout.style.iosAccessibilityAdjustsFontSize = true;
layout.style.fontScaleInternal = deviceFontScaleMock;
const nativeFontSize = testView.nativeTextViewProtected.font.pointSize;
const expectedNativeFontSize = testView.style.fontInternal.fontSize * deviceFontScaleMock;
TKUnit.assertEqual(nativeFontSize, expectedNativeFontSize, 'View font size does not respect a11y font scaling');
}
}

View File

@ -6,7 +6,7 @@ import { Span } from './span';
import { ObservableArray } from '../../data/observable-array';
import { ViewBase } from '../core/view-base';
import { Color } from '../../color';
import { FontStyle, FontWeight } from '../styling/font';
import { FontStyleType, FontWeightType } from '../styling/font';
import { CoreTypes } from '../../core-types';
/**
@ -36,12 +36,12 @@ export class FormattedString extends ViewBase {
/**
* Gets or sets the font style which will be used for all spans that doesn't have a specific value.
*/
public fontStyle: FontStyle;
public fontStyle: FontStyleType;
/**
* Gets or sets the font weight which will be used for all spans that doesn't have a specific value.
*/
public fontWeight: FontWeight;
public fontWeight: FontWeightType;
/**
* 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 {
* Gets or sets the font background color which will be used for all spans that doesn't have a specific value.
*/
public backgroundColor: Color;
/**
* Defines whether accessibility font scale should affect font size.
*/
iosAccessibilityAdjustsFontSize: boolean;
/**
* Gets or sets the minimum accessibility font scale.
*/
iosAccessibilityMinFontScale: number;
/**
* Gets or sets the maximum accessibility font scale.
*/
iosAccessibilityMaxFontScale: number;
}

View File

@ -66,6 +66,27 @@ export class FormattedString extends ViewBase implements FormattedStringDefiniti
this.style.backgroundColor = value;
}
get iosAccessibilityAdjustsFontSize(): boolean {
return this.style.iosAccessibilityAdjustsFontSize;
}
set iosAccessibilityAdjustsFontSize(value: boolean) {
this.style.iosAccessibilityAdjustsFontSize = value;
}
get iosAccessibilityMinFontScale(): number {
return this.style.iosAccessibilityMinFontScale;
}
set iosAccessibilityMinFontScale(value: number) {
this.style.iosAccessibilityMinFontScale = value;
}
get iosAccessibilityMaxFontScale(): number {
return this.style.iosAccessibilityMaxFontScale;
}
set iosAccessibilityMaxFontScale(value: number) {
this.style.iosAccessibilityMaxFontScale = value;
}
get spans(): ObservableArray<Span> {
if (!this._spans) {
this._spans = new ObservableArray<Span>();
@ -135,6 +156,12 @@ export class FormattedString extends ViewBase implements FormattedStringDefiniti
style.on('textDecorationChange', this.onPropertyChange, this);
style.on('colorChange', this.onPropertyChange, this);
style.on('backgroundColorChange', this.onPropertyChange, this);
// These handlers will trigger font scale update
style.on('iosAccessibilityAdjustsFontSizeChange', this.onPropertyChange, this);
style.on('iosAccessibilityMinFontScaleChange', this.onPropertyChange, this);
style.on('iosAccessibilityMaxFontScaleChange', this.onPropertyChange, this);
style.on('fontScaleInternalChange', this.onPropertyChange, this);
}
private removePropertyChangeHandler(span: Span) {
@ -147,6 +174,11 @@ export class FormattedString extends ViewBase implements FormattedStringDefiniti
style.off('textDecorationChange', this.onPropertyChange, this);
style.off('colorChange', this.onPropertyChange, this);
style.off('backgroundColorChange', this.onPropertyChange, this);
style.off('iosAccessibilityAdjustsFontSizeChange', this.onPropertyChange, this);
style.off('iosAccessibilityMinFontScaleChange', this.onPropertyChange, this);
style.off('iosAccessibilityMaxFontScaleChange', this.onPropertyChange, this);
style.off('fontScaleInternalChange', this.onPropertyChange, this);
}
private onPropertyChange(data: PropertyChangeData) {

View File

@ -194,28 +194,17 @@ export class TextBase extends TextBaseCommon {
[fontScaleInternalProperty.setNative](value: number) {
const nativeView = this.nativeTextViewProtected instanceof UIButton ? this.nativeTextViewProtected.titleLabel : this.nativeTextViewProtected;
const currentFont = this.style.fontInternal || Font.default.withFontSize(nativeView.font.pointSize);
let finalValue;
if (this.iosAccessibilityAdjustsFontSize) {
finalValue = value;
if (this.iosAccessibilityMinFontScale && this.iosAccessibilityMinFontScale > value) {
finalValue = this.iosAccessibilityMinFontScale;
}
if (this.iosAccessibilityMaxFontScale && this.iosAccessibilityMaxFontScale < value) {
finalValue = this.iosAccessibilityMaxFontScale;
}
} else {
finalValue = 1.0;
}
const newFont = currentFont.withFontScale(finalValue);
this.style.fontInternal = newFont;
const font = this.style.fontInternal || Font.default.withFontSize(nativeView.font.pointSize);
const finalValue = adjustMinMaxFontScale(value, this);
// Request layout on font scale as it's not done automatically
if (currentFont.fontScale !== finalValue) {
if (font.fontScale !== finalValue) {
this.style.fontInternal = font.withFontScale(finalValue);
this.requestLayout();
} else {
if (!this.style.fontInternal) {
this.style.fontInternal = font;
}
}
}
@ -360,7 +349,8 @@ export class TextBase extends TextBaseCommon {
}
createMutableStringDetails(span: Span, text: string, index?: number): any {
const font = new Font(span.style.fontFamily, span.style.fontSize, span.style.fontStyle, span.style.fontWeight);
const fontScale = adjustMinMaxFontScale(span.style.fontScaleInternal, span);
const font = new Font(span.style.fontFamily, span.style.fontSize, span.style.fontStyle, span.style.fontWeight, fontScale);
const iosFont = font.getUIFont(this.nativeTextViewProtected.font);
const backgroundColor = <Color>(span.style.backgroundColor || (<FormattedString>span.parent).backgroundColor || (<TextBase>span.parent.parent).backgroundColor);
@ -485,3 +475,20 @@ function isStringTappable(formattedString: FormattedString) {
return false;
}
function adjustMinMaxFontScale(value: number, view: TextBase | Span) {
let finalValue;
if (view.iosAccessibilityAdjustsFontSize) {
finalValue = value;
if (view.iosAccessibilityMinFontScale && view.iosAccessibilityMinFontScale > value) {
finalValue = view.iosAccessibilityMinFontScale;
}
if (view.iosAccessibilityMaxFontScale && view.iosAccessibilityMaxFontScale < value) {
finalValue = view.iosAccessibilityMaxFontScale;
}
} else {
finalValue = 1.0;
}
return finalValue;
}

View File

@ -1,6 +1,6 @@
import { Color } from '../../color';
import { ViewBase } from '../core/view-base';
import { FontStyle, FontWeight } from '../styling/font';
import { FontStyleType, FontWeightType } from '../styling/font';
import { CoreTypes } from '../../core-types';
/**
@ -20,12 +20,12 @@ export class Span extends ViewBase {
/**
* Gets or sets the font style of the span.
*/
public fontStyle: FontStyle;
public fontStyle: FontStyleType;
/**
* Gets or sets the font weight of the span.
*/
public fontWeight: FontWeight;
public fontWeight: FontWeightType;
/**
* Gets or sets text decorations for the span.
@ -42,6 +42,21 @@ export class Span extends ViewBase {
*/
public backgroundColor: Color;
/**
* Defines whether accessibility font scale should affect font size.
*/
iosAccessibilityAdjustsFontSize: boolean;
/**
* Gets or sets the minimum accessibility font scale.
*/
iosAccessibilityMinFontScale: number;
/**
* Gets or sets the maximum accessibility font scale.
*/
iosAccessibilityMaxFontScale: number;
/**
* Gets or sets the text for the span.
*/

View File

@ -62,6 +62,27 @@ export class Span extends ViewBase implements SpanDefinition {
this.style.backgroundColor = value;
}
get iosAccessibilityAdjustsFontSize(): boolean {
return this.style.iosAccessibilityAdjustsFontSize;
}
set iosAccessibilityAdjustsFontSize(value: boolean) {
this.style.iosAccessibilityAdjustsFontSize = value;
}
get iosAccessibilityMinFontScale(): number {
return this.style.iosAccessibilityMinFontScale;
}
set iosAccessibilityMinFontScale(value: number) {
this.style.iosAccessibilityMinFontScale = value;
}
get iosAccessibilityMaxFontScale(): number {
return this.style.iosAccessibilityMaxFontScale;
}
set iosAccessibilityMaxFontScale(value: number) {
this.style.iosAccessibilityMaxFontScale = value;
}
get text(): string {
return this._text;
}