mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-14 18:12:09 +08:00
fix(ios): FormattedString and Span a11y font scale (#10281)
This commit is contained in:

committed by
GitHub

parent
b8a548f009
commit
a14becdc6a
@ -227,6 +227,9 @@ allTests['LISTVIEW'] = listViewTests;
|
|||||||
import * as activityIndicatorTests from './ui/activity-indicator/activity-indicator-tests';
|
import * as activityIndicatorTests from './ui/activity-indicator/activity-indicator-tests';
|
||||||
allTests['ACTIVITY-INDICATOR'] = activityIndicatorTests;
|
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';
|
import * as textFieldTests from './ui/text-field/text-field-tests';
|
||||||
allTests['TEXT-FIELD'] = textFieldTests;
|
allTests['TEXT-FIELD'] = textFieldTests;
|
||||||
|
|
||||||
|
@ -580,26 +580,6 @@ export function test_setting_font_properties_sets_native_font() {
|
|||||||
test_native_font('italic', 'bold');
|
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') {
|
function test_native_font(style: 'normal' | 'italic', weight: '100' | '200' | '300' | 'normal' | '400' | '500' | '600' | 'bold' | '700' | '800' | '900') {
|
||||||
const testView = new Button();
|
const testView = new Button();
|
||||||
|
|
||||||
|
23
apps/automated/src/ui/text-base/text-base-tests.ts
Normal file
23
apps/automated/src/ui/text-base/text-base-tests.ts
Normal 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');
|
||||||
|
}
|
||||||
|
}
|
21
packages/core/ui/text-base/formatted-string.d.ts
vendored
21
packages/core/ui/text-base/formatted-string.d.ts
vendored
@ -6,7 +6,7 @@ import { Span } from './span';
|
|||||||
import { ObservableArray } from '../../data/observable-array';
|
import { ObservableArray } from '../../data/observable-array';
|
||||||
import { ViewBase } from '../core/view-base';
|
import { ViewBase } from '../core/view-base';
|
||||||
import { Color } from '../../color';
|
import { Color } from '../../color';
|
||||||
import { FontStyle, FontWeight } from '../styling/font';
|
import { FontStyleType, FontWeightType } from '../styling/font';
|
||||||
import { CoreTypes } from '../../core-types';
|
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.
|
* 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.
|
* 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.
|
* 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.
|
* Gets or sets the font background color which will be used for all spans that doesn't have a specific value.
|
||||||
*/
|
*/
|
||||||
public backgroundColor: Color;
|
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;
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,27 @@ export class FormattedString extends ViewBase implements FormattedStringDefiniti
|
|||||||
this.style.backgroundColor = value;
|
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> {
|
get spans(): ObservableArray<Span> {
|
||||||
if (!this._spans) {
|
if (!this._spans) {
|
||||||
this._spans = new ObservableArray<Span>();
|
this._spans = new ObservableArray<Span>();
|
||||||
@ -135,6 +156,12 @@ export class FormattedString extends ViewBase implements FormattedStringDefiniti
|
|||||||
style.on('textDecorationChange', this.onPropertyChange, this);
|
style.on('textDecorationChange', this.onPropertyChange, this);
|
||||||
style.on('colorChange', this.onPropertyChange, this);
|
style.on('colorChange', this.onPropertyChange, this);
|
||||||
style.on('backgroundColorChange', 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) {
|
private removePropertyChangeHandler(span: Span) {
|
||||||
@ -147,6 +174,11 @@ export class FormattedString extends ViewBase implements FormattedStringDefiniti
|
|||||||
style.off('textDecorationChange', this.onPropertyChange, this);
|
style.off('textDecorationChange', this.onPropertyChange, this);
|
||||||
style.off('colorChange', this.onPropertyChange, this);
|
style.off('colorChange', this.onPropertyChange, this);
|
||||||
style.off('backgroundColorChange', 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) {
|
private onPropertyChange(data: PropertyChangeData) {
|
||||||
|
@ -194,28 +194,17 @@ export class TextBase extends TextBaseCommon {
|
|||||||
|
|
||||||
[fontScaleInternalProperty.setNative](value: number) {
|
[fontScaleInternalProperty.setNative](value: number) {
|
||||||
const nativeView = this.nativeTextViewProtected instanceof UIButton ? this.nativeTextViewProtected.titleLabel : this.nativeTextViewProtected;
|
const nativeView = this.nativeTextViewProtected instanceof UIButton ? this.nativeTextViewProtected.titleLabel : this.nativeTextViewProtected;
|
||||||
const currentFont = this.style.fontInternal || Font.default.withFontSize(nativeView.font.pointSize);
|
const font = this.style.fontInternal || Font.default.withFontSize(nativeView.font.pointSize);
|
||||||
|
const finalValue = adjustMinMaxFontScale(value, this);
|
||||||
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;
|
|
||||||
|
|
||||||
// Request layout on font scale as it's not done automatically
|
// 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();
|
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 {
|
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 iosFont = font.getUIFont(this.nativeTextViewProtected.font);
|
||||||
|
|
||||||
const backgroundColor = <Color>(span.style.backgroundColor || (<FormattedString>span.parent).backgroundColor || (<TextBase>span.parent.parent).backgroundColor);
|
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;
|
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;
|
||||||
|
}
|
||||||
|
21
packages/core/ui/text-base/span.d.ts
vendored
21
packages/core/ui/text-base/span.d.ts
vendored
@ -1,6 +1,6 @@
|
|||||||
import { Color } from '../../color';
|
import { Color } from '../../color';
|
||||||
import { ViewBase } from '../core/view-base';
|
import { ViewBase } from '../core/view-base';
|
||||||
import { FontStyle, FontWeight } from '../styling/font';
|
import { FontStyleType, FontWeightType } from '../styling/font';
|
||||||
import { CoreTypes } from '../../core-types';
|
import { CoreTypes } from '../../core-types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -20,12 +20,12 @@ export class Span extends ViewBase {
|
|||||||
/**
|
/**
|
||||||
* Gets or sets the font style of the span.
|
* Gets or sets the font style of the span.
|
||||||
*/
|
*/
|
||||||
public fontStyle: FontStyle;
|
public fontStyle: FontStyleType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets or sets the font weight of the span.
|
* Gets or sets the font weight of the span.
|
||||||
*/
|
*/
|
||||||
public fontWeight: FontWeight;
|
public fontWeight: FontWeightType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets or sets text decorations for the span.
|
* Gets or sets text decorations for the span.
|
||||||
@ -42,6 +42,21 @@ export class Span extends ViewBase {
|
|||||||
*/
|
*/
|
||||||
public backgroundColor: Color;
|
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.
|
* Gets or sets the text for the span.
|
||||||
*/
|
*/
|
||||||
|
@ -62,6 +62,27 @@ export class Span extends ViewBase implements SpanDefinition {
|
|||||||
this.style.backgroundColor = value;
|
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 {
|
get text(): string {
|
||||||
return this._text;
|
return this._text;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user