mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-26 11:17:04 +08:00
feat(ios): new a11y properties for managing font scale (#10260)
This commit is contained in:

committed by
GitHub

parent
2f9e5c0b84
commit
7aaa1d899d
@ -0,0 +1,70 @@
|
||||
import * as TKUnit from '../tk-unit';
|
||||
import * as helper from '../ui-helper';
|
||||
import { isIOS, Label, StackLayout } from '@nativescript/core';
|
||||
|
||||
export function test_iosAccessibilityAdjustsFontSize_property() {
|
||||
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 = false;
|
||||
layout.style.fontScaleInternal = deviceFontScaleMock;
|
||||
|
||||
const nativeFontSize = testView.nativeTextViewProtected.font.pointSize;
|
||||
layout.style.iosAccessibilityAdjustsFontSize = true;
|
||||
const nativeFontSizeWithAdjust = testView.nativeTextViewProtected.font.pointSize;
|
||||
|
||||
TKUnit.assertEqual(nativeFontSize, testView.style.fontInternal.fontSize, 'View font size was scaled even though iosAccessibilityAdjustsFontSize is disabled');
|
||||
TKUnit.assertEqual(nativeFontSizeWithAdjust, testView.style.fontInternal.fontSize * deviceFontScaleMock, 'View font size was not scaled even though iosAccessibilityAdjustsFontSize is enabled');
|
||||
}
|
||||
}
|
||||
|
||||
export function test_iosAccessibilityMinFontScale_property() {
|
||||
if (isIOS) {
|
||||
const deviceFontScaleMock = 1.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;
|
||||
|
||||
testView.style.iosAccessibilityMinFontScale = 2.0;
|
||||
|
||||
const nativeFontSize = testView.nativeTextViewProtected.font.pointSize;
|
||||
const expectedNativeFontSize = testView.style.fontInternal.fontSize * testView.style.iosAccessibilityMinFontScale;
|
||||
TKUnit.assertEqual(nativeFontSize, expectedNativeFontSize, 'View font size scaling does not respect iosAccessibilityMinFontScale');
|
||||
}
|
||||
}
|
||||
|
||||
export function test_iosAccessibilityMaxFontScale_property() {
|
||||
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;
|
||||
|
||||
testView.style.iosAccessibilityMaxFontScale = 2.0;
|
||||
|
||||
const nativeFontSize = testView.nativeTextViewProtected.font.pointSize;
|
||||
const expectedNativeFontSize = testView.style.fontInternal.fontSize * testView.style.iosAccessibilityMaxFontScale;
|
||||
TKUnit.assertEqual(nativeFontSize, expectedNativeFontSize, 'View font size scaling does not respect iosAccessibilityMaxFontScale');
|
||||
}
|
||||
}
|
@ -54,6 +54,9 @@ if (!__CI__) {
|
||||
allTests['PROFILING'] = profilingTests;
|
||||
}
|
||||
|
||||
import * as a11yPropertiesTests from './accessibility/accessibility-properties-tests';
|
||||
allTests['A11Y-PROPERTIES'] = a11yPropertiesTests;
|
||||
|
||||
import * as appSettingsTests from './application-settings/application-settings-tests';
|
||||
allTests['APPLICATION-SETTINGS'] = appSettingsTests;
|
||||
|
||||
|
@ -582,13 +582,17 @@ export function test_setting_font_properties_sets_native_font() {
|
||||
|
||||
export function test_native_font_size_with_a11y_font_scale() {
|
||||
if (isIOS) {
|
||||
const page = helper.getCurrentPage();
|
||||
const testView = new Label();
|
||||
const deviceFontScaleMock = 4.0;
|
||||
|
||||
page.content = testView;
|
||||
const page = helper.getCurrentPage();
|
||||
const testView = new Label();
|
||||
const layout = new StackLayout();
|
||||
layout.addChild(testView);
|
||||
|
||||
testView.style._fontScale = deviceFontScaleMock;
|
||||
page.content = layout;
|
||||
|
||||
layout.style.iosAccessibilityAdjustsFontSize = true;
|
||||
layout.style.fontScaleInternal = deviceFontScaleMock;
|
||||
|
||||
const nativeFontSize = testView.nativeTextViewProtected.font.pointSize;
|
||||
const expectedNativeFontSize = testView.style.fontInternal.fontSize * deviceFontScaleMock;
|
||||
|
@ -52,10 +52,10 @@ function applyFontScaleToRootViews(): void {
|
||||
|
||||
const fontScale = getCurrentFontScale();
|
||||
|
||||
rootView.style._fontScale = fontScale;
|
||||
rootView.style.fontScaleInternal = fontScale;
|
||||
|
||||
const rootModalViews = <Array<View>>rootView._getRootModalViews();
|
||||
rootModalViews.forEach((rootModalView) => (rootModalView.style._fontScale = fontScale));
|
||||
rootModalViews.forEach((rootModalView) => (rootModalView.style.fontScaleInternal = fontScale));
|
||||
}
|
||||
|
||||
export function initAccessibilityCssHelper(): void {
|
||||
|
@ -31,6 +31,30 @@ export const accessibilityEnabledProperty = new CssProperty<Style, boolean>({
|
||||
});
|
||||
accessibilityEnabledProperty.register(Style);
|
||||
|
||||
export const iosAccessibilityAdjustsFontSizeProperty = new InheritedCssProperty<Style, boolean>({
|
||||
defaultValue: false,
|
||||
name: 'iosAccessibilityAdjustsFontSize',
|
||||
cssName: 'ios-a11y-adjusts-font-size',
|
||||
valueConverter: booleanConverter,
|
||||
});
|
||||
iosAccessibilityAdjustsFontSizeProperty.register(Style);
|
||||
|
||||
export const iosAccessibilityMinFontScaleProperty = new InheritedCssProperty<Style, number>({
|
||||
defaultValue: 0,
|
||||
name: 'iosAccessibilityMinFontScale',
|
||||
cssName: 'ios-a11y-min-font-scale',
|
||||
valueConverter: parseFloat,
|
||||
});
|
||||
iosAccessibilityMinFontScaleProperty.register(Style);
|
||||
|
||||
export const iosAccessibilityMaxFontScaleProperty = new InheritedCssProperty<Style, number>({
|
||||
defaultValue: 0,
|
||||
name: 'iosAccessibilityMaxFontScale',
|
||||
cssName: 'ios-a11y-max-font-scale',
|
||||
valueConverter: parseFloat,
|
||||
});
|
||||
iosAccessibilityMaxFontScaleProperty.register(Style);
|
||||
|
||||
export const accessibilityHiddenProperty = new (global.isIOS ? InheritedCssProperty : CssProperty)({
|
||||
name: 'accessibilityHidden',
|
||||
cssName: 'a11y-hidden',
|
||||
|
15
packages/core/ui/core/view/index.d.ts
vendored
15
packages/core/ui/core/view/index.d.ts
vendored
@ -282,6 +282,21 @@ export abstract class View extends ViewCommon {
|
||||
*/
|
||||
accessibilityMediaSession: boolean;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Internal use only. This is used to limit the number of updates to android.view.View.setContentDescription()
|
||||
*/
|
||||
|
@ -405,7 +405,7 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
|
||||
modalRootViewCssClasses.forEach((c) => this.cssClasses.add(c));
|
||||
|
||||
parent._modal = this;
|
||||
this.style._fontScale = getCurrentFontScale();
|
||||
this.style.fontScaleInternal = getCurrentFontScale();
|
||||
this._modalParent = parent;
|
||||
this._modalContext = options.context;
|
||||
this._closeModalCallback = (...originalArgs) => {
|
||||
@ -859,6 +859,27 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
|
||||
this.style.accessibilityMediaSession = 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 automationText(): string {
|
||||
return this.accessibilityIdentifier;
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ import { TransformFunctionsInfo } from '../animation';
|
||||
import { CoreTypes } from '../../core-types';
|
||||
import { Color } from '../../color';
|
||||
import { CssProperty, CssAnimationProperty, ShorthandProperty, InheritedCssProperty } from '../core/properties';
|
||||
import { Style } from '../styling/style';
|
||||
import { Font, FontStyle, FontWeight } from './font';
|
||||
import { Style } from './style';
|
||||
import { Font, FontStyleType, FontWeightType } from './font';
|
||||
import { Background } from './background';
|
||||
|
||||
export namespace Length {
|
||||
@ -95,11 +95,12 @@ export const verticalAlignmentProperty: CssProperty<Style, CoreTypes.VerticalAli
|
||||
|
||||
export const fontSizeProperty: InheritedCssProperty<Style, number>;
|
||||
export const fontFamilyProperty: InheritedCssProperty<Style, string>;
|
||||
export const fontStyleProperty: InheritedCssProperty<Style, FontStyle>;
|
||||
export const fontWeightProperty: InheritedCssProperty<Style, FontWeight>;
|
||||
export const fontStyleProperty: InheritedCssProperty<Style, FontStyleType>;
|
||||
export const fontWeightProperty: InheritedCssProperty<Style, FontWeightType>;
|
||||
|
||||
export const backgroundInternalProperty: CssProperty<Style, Background>;
|
||||
export const fontInternalProperty: InheritedCssProperty<Style, Font>;
|
||||
export const fontScaleInternalProperty: InheritedCssProperty<Style, number>;
|
||||
|
||||
export const androidElevationProperty: CssProperty<Style, number>;
|
||||
export const androidDynamicElevationOffsetProperty: CssProperty<Style, number>;
|
||||
|
@ -1,12 +1,12 @@
|
||||
// Types
|
||||
import { unsetValue, CssProperty, CssAnimationProperty, ShorthandProperty, InheritedCssProperty } from '../core/properties';
|
||||
import { Style } from '../styling/style';
|
||||
import { Style } from './style';
|
||||
import { Transformation, TransformationValue, TransformFunctionsInfo } from '../animation';
|
||||
|
||||
import { Color } from '../../color';
|
||||
import { Font, parseFont, FontStyle, FontStyleType, FontWeight, FontWeightType, FontVariationSettings, FontVariationSettingsType } from '../../ui/styling/font';
|
||||
import { Font, parseFont, FontStyle, FontStyleType, FontWeight, FontWeightType, FontVariationSettings, FontVariationSettingsType } from './font';
|
||||
import { Background } from './background';
|
||||
import { layout, hasDuplicates } from '../../utils';
|
||||
import { Background } from '../../ui/styling/background';
|
||||
|
||||
import { radiansToDegrees } from '../../utils/number-utils';
|
||||
|
||||
@ -1326,13 +1326,13 @@ export const fontFamilyProperty = new InheritedCssProperty<Style, string>({
|
||||
});
|
||||
fontFamilyProperty.register(Style);
|
||||
|
||||
export const fontScaleProperty = new InheritedCssProperty<Style, number>({
|
||||
name: '_fontScale',
|
||||
cssName: '_fontScale',
|
||||
export const fontScaleInternalProperty = new InheritedCssProperty<Style, number>({
|
||||
name: 'fontScaleInternal',
|
||||
cssName: '_fontScaleInternal',
|
||||
defaultValue: 1.0,
|
||||
valueConverter: (v) => parseFloat(v),
|
||||
});
|
||||
fontScaleProperty.register(Style);
|
||||
fontScaleInternalProperty.register(Style);
|
||||
|
||||
export const fontSizeProperty = new InheritedCssProperty<Style, number>({
|
||||
name: 'fontSize',
|
||||
|
@ -108,7 +108,7 @@ export class Style extends Observable implements StyleDefinition {
|
||||
/**
|
||||
* This property ensures inheritance of a11y scale among views.
|
||||
*/
|
||||
public _fontScale: number;
|
||||
public fontScaleInternal: number;
|
||||
public backgroundInternal: Background;
|
||||
|
||||
public rotate: number;
|
||||
@ -233,6 +233,9 @@ export class Style extends Observable implements StyleDefinition {
|
||||
public accessibilityLanguage: string;
|
||||
public accessibilityMediaSession: boolean;
|
||||
public accessibilityStep: number;
|
||||
public iosAccessibilityAdjustsFontSize: boolean;
|
||||
public iosAccessibilityMinFontScale: number;
|
||||
public iosAccessibilityMaxFontScale: number;
|
||||
|
||||
public PropertyBag: {
|
||||
new (): { [property: string]: string };
|
||||
|
@ -4,11 +4,12 @@ import { CSSShadow } from '../styling/css-shadow';
|
||||
|
||||
// Requires
|
||||
import { Font } from '../styling/font';
|
||||
import { iosAccessibilityAdjustsFontSizeProperty, iosAccessibilityMaxFontScaleProperty, iosAccessibilityMinFontScaleProperty } from '../../accessibility/accessibility-properties';
|
||||
import { TextBaseCommon, textProperty, formattedTextProperty, textAlignmentProperty, textDecorationProperty, textTransformProperty, textShadowProperty, letterSpacingProperty, lineHeightProperty, maxLinesProperty, resetSymbol } from './text-base-common';
|
||||
import { Color } from '../../color';
|
||||
import { FormattedString } from './formatted-string';
|
||||
import { Span } from './span';
|
||||
import { colorProperty, fontInternalProperty, fontScaleProperty, Length } from '../styling/style-properties';
|
||||
import { colorProperty, fontInternalProperty, fontScaleInternalProperty, Length } from '../styling/style-properties';
|
||||
import { isString, isNullOrUndefined } from '../../utils/types';
|
||||
import { iOSNativeHelper } from '../../utils';
|
||||
import { Trace } from '../../trace';
|
||||
@ -187,29 +188,49 @@ export class TextBase extends TextBaseCommon {
|
||||
if (!(value instanceof Font) || !this.formattedText) {
|
||||
let nativeView = this.nativeTextViewProtected;
|
||||
nativeView = nativeView instanceof UIButton ? nativeView.titleLabel : nativeView;
|
||||
|
||||
if (value instanceof Font) {
|
||||
// Apply a11y font scale if not set
|
||||
if (value.fontScale !== this.style._fontScale) {
|
||||
value.fontScale = this.style._fontScale;
|
||||
}
|
||||
nativeView.font = value.getUIFont(nativeView.font);
|
||||
} else {
|
||||
nativeView.font = value;
|
||||
}
|
||||
nativeView.font = value instanceof Font ? value.getUIFont(nativeView.font) : value;
|
||||
}
|
||||
}
|
||||
|
||||
[fontScaleProperty.setNative](value: number) {
|
||||
[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);
|
||||
if (currentFont.fontScale !== value) {
|
||||
const newFont = currentFont.withFontScale(value);
|
||||
|
||||
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
|
||||
if (currentFont.fontScale !== finalValue) {
|
||||
this.requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
[iosAccessibilityAdjustsFontSizeProperty.setNative](value: boolean) {
|
||||
this[fontScaleInternalProperty.setNative](this.style.fontScaleInternal);
|
||||
}
|
||||
|
||||
[iosAccessibilityMinFontScaleProperty.setNative](value: number) {
|
||||
this[fontScaleInternalProperty.setNative](this.style.fontScaleInternal);
|
||||
}
|
||||
|
||||
[iosAccessibilityMaxFontScaleProperty.setNative](value: number) {
|
||||
this[fontScaleInternalProperty.setNative](this.style.fontScaleInternal);
|
||||
}
|
||||
|
||||
[textAlignmentProperty.setNative](value: CoreTypes.TextAlignmentType) {
|
||||
const nativeView = <UITextField | UITextView | UILabel>this.nativeTextViewProtected;
|
||||
switch (value) {
|
||||
|
Reference in New Issue
Block a user