mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-03-06 22:37:14 +08:00
Create a cross-platform accessibility example module (#23722)
Summary: This PR divides the accessibility tests into two activities-- a cross-platform activity for accessibility features which are expected to work on all platforms, and platform specific tests for Android and iOS. We believe that most, if not all, accessibility features should be cross-platform, with fallback implementations where the underlying concept doesn't exist on a particular platform. This division of the tests makes it clearer for developers which features are expected to work on all supported platforms, and which are platform-specific. [CATEGORY] general, Android, iOS [TYPE] change Message Refactor the RNTester accessibility activities to better represent where the features are expected to work. Moves all cross-platform tests to AccessibilityExample.js, Android-specific tests to AccessibilityAndroidExample.android.js, and iOS-specific tests to AccessibilityIOsExample.ios.js. Pull Request resolved: https://github.com/facebook/react-native/pull/23722 Differential Revision: D14320696 Pulled By: cpojer fbshipit-source-id: b5ab7a82a90f06d55a24262e86bd69fbdc890427
This commit is contained in:
committed by
Facebook Github Bot
parent
ba6f818d7d
commit
1889b797d3
@@ -35,32 +35,6 @@ class AccessibilityAndroidExample extends React.Component {
|
||||
count: 0,
|
||||
backgroundImportantForAcc: 0,
|
||||
forgroundImportantForAcc: 0,
|
||||
screenReaderEnabled: false,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
AccessibilityInfo.addEventListener(
|
||||
'change',
|
||||
this._handleScreenReaderToggled,
|
||||
);
|
||||
AccessibilityInfo.fetch().done(isEnabled => {
|
||||
this.setState({
|
||||
screenReaderEnabled: isEnabled,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
AccessibilityInfo.removeEventListener(
|
||||
'change',
|
||||
this._handleScreenReaderToggled,
|
||||
);
|
||||
}
|
||||
|
||||
_handleScreenReaderToggled = isEnabled => {
|
||||
this.setState({
|
||||
screenReaderEnabled: isEnabled,
|
||||
});
|
||||
};
|
||||
|
||||
_addOne = () => {
|
||||
@@ -83,134 +57,7 @@ class AccessibilityAndroidExample extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<RNTesterPage title={'Accessibility'}>
|
||||
<RNTesterBlock title="Nonaccessible view with TextViews">
|
||||
<View>
|
||||
<Text style={{color: 'green'}}>This is</Text>
|
||||
<Text style={{color: 'blue'}}>nontouchable normal view.</Text>
|
||||
</View>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Accessible view with TextViews wihout label">
|
||||
<View accessible={true}>
|
||||
<Text style={{color: 'green'}}>This is</Text>
|
||||
<Text style={{color: 'blue'}}>
|
||||
nontouchable accessible view without label.
|
||||
</Text>
|
||||
</View>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Accessible view with TextViews with label">
|
||||
<View
|
||||
accessible={true}
|
||||
accessibilityLabel="I have label, so I read it instead of embedded text.">
|
||||
<Text style={{color: 'green'}}>This is</Text>
|
||||
<Text style={{color: 'blue'}}>
|
||||
nontouchable accessible view with label.
|
||||
</Text>
|
||||
</View>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Touchable with accessibilityRole = header">
|
||||
<View
|
||||
accessible={true}
|
||||
accessibilityLabel="I'm a header, so I read it instead of embedded text."
|
||||
accessibilityRole="header">
|
||||
<Text style={{color: 'green'}}>This is</Text>
|
||||
<Text style={{color: 'blue'}}>
|
||||
nontouchable accessible view with label.
|
||||
</Text>
|
||||
</View>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Touchable with accessibilityRole = link">
|
||||
<TouchableWithoutFeedback
|
||||
onPress={() =>
|
||||
ToastAndroid.show('Toasts work by default', ToastAndroid.SHORT)
|
||||
}
|
||||
accessibilityRole="link">
|
||||
<View style={styles.embedded}>
|
||||
<Text>Click me</Text>
|
||||
<Text>Or not</Text>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Touchable with accessibilityRole = button">
|
||||
<TouchableWithoutFeedback
|
||||
onPress={() =>
|
||||
ToastAndroid.show('Toasts work by default', ToastAndroid.SHORT)
|
||||
}
|
||||
accessibilityRole="button">
|
||||
<View style={styles.embedded}>
|
||||
<Text>Click me</Text>
|
||||
<Text>Or not</Text>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Disabled Touchable with accessibilityRole = button">
|
||||
<TouchableWithoutFeedback
|
||||
onPress={() =>
|
||||
ToastAndroid.show('Toasts work by default', ToastAndroid.SHORT)
|
||||
}
|
||||
accessibilityRole="button"
|
||||
accessibilityStates={['disabled']}
|
||||
disabled={true}>
|
||||
<View>
|
||||
<Text>I am disabled</Text>
|
||||
<Text>Clicking me will not trigger any action.</Text>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Touchable with accessibilityRole = button and accessibilityHint">
|
||||
<TouchableWithoutFeedback
|
||||
onPress={() =>
|
||||
ToastAndroid.show('Toasts work by default', ToastAndroid.SHORT)
|
||||
}
|
||||
accessibilityRole="button"
|
||||
accessibilityHint="Triggers
|
||||
Toasts">
|
||||
<View>
|
||||
<Text>Click Me!</Text>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Accessible View with hint, role, and state">
|
||||
<View
|
||||
accessible={true}
|
||||
accessibilityRole="button"
|
||||
accessibilityStates={['selected']}
|
||||
accessibilityHint="accessibility hint">
|
||||
<Text>Accessible view with hint, role, and state</Text>
|
||||
<Text style={{color: 'gray'}}>
|
||||
Talkback will say: accessibility hint button, selected{' '}
|
||||
</Text>
|
||||
</View>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Accessible View with label, hint, role, and state">
|
||||
<View
|
||||
accessible={true}
|
||||
accessibilityLabel="accessibility Label"
|
||||
accessibilityRole="button"
|
||||
accessibilityStates={['selected']}
|
||||
accessibilityHint="accessibility Hint">
|
||||
<Text>Accessible view with label, hint, role, and state</Text>
|
||||
<Text style={{color: 'gray'}}>
|
||||
Talkback will say: accessibility label, hint button, selected{' '}
|
||||
</Text>
|
||||
</View>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Accessible View with no other properties set">
|
||||
<View accessible={true}>
|
||||
<Text>This accessible view has no label, so the text is read.</Text>
|
||||
</View>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterPage title={'Accessibility Android APIs'}>
|
||||
<RNTesterBlock title="LiveRegion">
|
||||
<TouchableWithoutFeedback onPress={this._addOne}>
|
||||
<View style={styles.embedded}>
|
||||
@@ -222,13 +69,6 @@ class AccessibilityAndroidExample extends React.Component {
|
||||
</Text>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Check if the screen reader is enabled">
|
||||
<Text>
|
||||
The screen reader is{' '}
|
||||
{this.state.screenReaderEnabled ? 'enabled' : 'disabled'}.
|
||||
</Text>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Overlapping views and importantForAccessibility property">
|
||||
<View style={styles.container}>
|
||||
<View
|
||||
@@ -328,8 +168,8 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
});
|
||||
|
||||
exports.title = 'Accessibility';
|
||||
exports.description = 'Examples of using Accessibility API.';
|
||||
exports.title = 'AccessibilityAndroid';
|
||||
exports.description = 'Android specific Accessibility APIs.';
|
||||
exports.examples = [
|
||||
{
|
||||
title: 'Accessibility elements',
|
||||
|
||||
193
RNTester/js/AccessibilityExample.js
Normal file
193
RNTester/js/AccessibilityExample.js
Normal file
@@ -0,0 +1,193 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
const {AccessibilityInfo, Text, View, TouchableOpacity, Alert} = ReactNative;
|
||||
|
||||
const RNTesterBlock = require('./RNTesterBlock');
|
||||
|
||||
class AccessibilityExample extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<RNTesterBlock title="TextView without label">
|
||||
<Text>
|
||||
Text's accessibilityLabel is the raw text itself unless it is set
|
||||
explicitly.
|
||||
</Text>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="TextView with label">
|
||||
<Text accessibilityLabel="I have label, so I read it instead of embedded text.">
|
||||
This text component's accessibilityLabel is set explicitly.
|
||||
</Text>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Nonaccessible view with TextViews">
|
||||
<View>
|
||||
<Text style={{color: 'green'}}>This is text one.</Text>
|
||||
<Text style={{color: 'blue'}}>This is text two.</Text>
|
||||
</View>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Accessible view with TextViews wihout label">
|
||||
<View accessible={true}>
|
||||
<Text style={{color: 'green'}}>This is text one.</Text>
|
||||
<Text style={{color: 'blue'}}>This is text two.</Text>
|
||||
</View>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Accessible view with TextViews with label">
|
||||
<View
|
||||
accessible={true}
|
||||
accessibilityLabel="I have label, so I read it instead of embedded text.">
|
||||
<Text style={{color: 'green'}}>This is text one.</Text>
|
||||
<Text style={{color: 'blue'}}>This is text two.</Text>
|
||||
</View>
|
||||
</RNTesterBlock>
|
||||
|
||||
{/* Android screen readers will say the accessibility hint instead of the text
|
||||
since the view doesn't have a label. */}
|
||||
<RNTesterBlock title="Accessible view with TextViews with hint">
|
||||
<View accessibilityHint="Accessibility hint." accessible={true}>
|
||||
<Text style={{color: 'green'}}>This is text one.</Text>
|
||||
<Text style={{color: 'blue'}}>This is text two.</Text>
|
||||
</View>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Accessible view TextViews with label and hint">
|
||||
<View
|
||||
accessibilityLabel="Accessibility label."
|
||||
accessibilityHint="Accessibility hint."
|
||||
accessible={true}>
|
||||
<Text style={{color: 'green'}}>This is text one.</Text>
|
||||
<Text style={{color: 'blue'}}>This is text two.</Text>
|
||||
</View>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Text with accessibilityRole = header">
|
||||
<Text accessibilityRole="header">This is a title.</Text>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Touchable with accessibilityRole = link">
|
||||
<TouchableOpacity
|
||||
onPress={() => Alert.alert('Link has been clicked!')}
|
||||
accessibilityRole="link">
|
||||
<View>
|
||||
<Text>Click me</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Touchable with accessibilityRole = button">
|
||||
<TouchableOpacity
|
||||
onPress={() => Alert.alert('Button has been pressed!')}
|
||||
accessibilityRole="button">
|
||||
<Text>Click me</Text>
|
||||
</TouchableOpacity>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="Disabled Touchable with role">
|
||||
<TouchableOpacity
|
||||
onPress={() => Alert.alert('Button has been pressed!')}
|
||||
accessibilityRole="button"
|
||||
accessibilityStates={['disabled']}
|
||||
disabled={true}>
|
||||
<View>
|
||||
<Text>
|
||||
I am disabled. Clicking me will not trigger any action.
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="View with multiple states">
|
||||
<View
|
||||
accessible={true}
|
||||
accessibilityStates={['selected', 'disabled']}>
|
||||
<Text>This view is selected and disabled.</Text>
|
||||
</View>
|
||||
</RNTesterBlock>
|
||||
|
||||
<RNTesterBlock title="View with label, hint, role, and state">
|
||||
<View
|
||||
accessible={true}
|
||||
accessibilityLabel="Accessibility label."
|
||||
accessibilityRole="button"
|
||||
accessibilityStates={['selected']}
|
||||
accessibilityHint="Accessibility hint.">
|
||||
<Text>Accessible view with label, hint, role, and state</Text>
|
||||
</View>
|
||||
</RNTesterBlock>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ScreenReaderStatusExample extends React.Component<{}> {
|
||||
state = {
|
||||
screenReaderEnabled: false,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
AccessibilityInfo.addEventListener(
|
||||
'change',
|
||||
this._handleScreenReaderToggled,
|
||||
);
|
||||
AccessibilityInfo.fetch().done(isEnabled => {
|
||||
this.setState({
|
||||
screenReaderEnabled: isEnabled,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
AccessibilityInfo.removeEventListener(
|
||||
'change',
|
||||
this._handleScreenReaderToggled,
|
||||
);
|
||||
}
|
||||
|
||||
_handleScreenReaderToggled = isEnabled => {
|
||||
this.setState({
|
||||
screenReaderEnabled: isEnabled,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<Text>
|
||||
The screen reader is{' '}
|
||||
{this.state.screenReaderEnabled ? 'enabled' : 'disabled'}.
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
exports.title = 'Accessibility';
|
||||
exports.description = 'Examples of using Accessibility APIs.';
|
||||
exports.examples = [
|
||||
{
|
||||
title: 'Accessibility elements',
|
||||
render(): React.Element<typeof AccessibilityExample> {
|
||||
return <AccessibilityExample />;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Check if the screen reader is enabled',
|
||||
render(): React.Element<typeof ScreenReaderStatusExample> {
|
||||
return <ScreenReaderStatusExample />;
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -14,11 +14,13 @@ const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
const {AccessibilityInfo, Text, View, TouchableOpacity, Alert} = ReactNative;
|
||||
|
||||
const RNTesterBlock = require('./RNTesterBlock');
|
||||
|
||||
type Props = $ReadOnly<{||}>;
|
||||
class AccessibilityIOSExample extends React.Component<Props> {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<RNTesterBlock title="Accessibility iOS APIs">
|
||||
<View
|
||||
onAccessibilityTap={() =>
|
||||
Alert.alert('Alert', 'onAccessibilityTap success')
|
||||
@@ -36,112 +38,23 @@ class AccessibilityIOSExample extends React.Component<Props> {
|
||||
accessible={true}>
|
||||
<Text>Accessibility escape example</Text>
|
||||
</View>
|
||||
<View accessibilityLabel="Some announcement" accessible={true}>
|
||||
<Text>Accessibility label example</Text>
|
||||
</View>
|
||||
<View
|
||||
accessibilityRole="button"
|
||||
accessibilityStates={['selected']}
|
||||
accessible={true}>
|
||||
<Text>Accessibility traits example</Text>
|
||||
</View>
|
||||
<Text>
|
||||
Text's accessibilityLabel is the raw text itself unless it is set
|
||||
explicitly.
|
||||
</Text>
|
||||
<Text accessibilityLabel="Test of accessibilityLabel" accessible={true}>
|
||||
This text component's accessibilityLabel is set explicitly.
|
||||
</Text>
|
||||
<View
|
||||
accessibilityLabel="Test of accessibilityHint"
|
||||
accessibilityHint="The hint provides more info than the label does"
|
||||
accessible={true}>
|
||||
<Text>
|
||||
This view component has both an accessibilityLabel and an
|
||||
accessibilityHint explicitly set.
|
||||
</Text>
|
||||
</View>
|
||||
<Text
|
||||
accessibilityLabel="Test of accessibilityHint"
|
||||
accessibilityHint="The hint provides more info than the label does">
|
||||
This text component has both an accessibilityLabel and an
|
||||
accessibilityHint explicitly set.
|
||||
</Text>
|
||||
<TouchableOpacity
|
||||
accessibilityLabel="Test of accessibilityHint"
|
||||
accessibilityHint="The hint provides more info than the label does">
|
||||
<View>
|
||||
<Text>
|
||||
This button has both an accessibilityLabel and an
|
||||
accessibilityHint explicitly set.
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
<View accessibilityElementsHidden={true}>
|
||||
<Text>
|
||||
This view's children are hidden from the accessibility tree
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ScreenReaderStatusExample extends React.Component<{}, $FlowFixMeState> {
|
||||
state = {
|
||||
screenReaderEnabled: false,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
AccessibilityInfo.addEventListener(
|
||||
'change',
|
||||
this._handleScreenReaderToggled,
|
||||
);
|
||||
AccessibilityInfo.fetch().done(isEnabled => {
|
||||
this.setState({
|
||||
screenReaderEnabled: isEnabled,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
AccessibilityInfo.removeEventListener(
|
||||
'change',
|
||||
this._handleScreenReaderToggled,
|
||||
);
|
||||
}
|
||||
|
||||
_handleScreenReaderToggled = isEnabled => {
|
||||
this.setState({
|
||||
screenReaderEnabled: isEnabled,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<Text>
|
||||
The screen reader is{' '}
|
||||
{this.state.screenReaderEnabled ? 'enabled' : 'disabled'}.
|
||||
</Text>
|
||||
</View>
|
||||
</RNTesterBlock>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
exports.title = 'AccessibilityIOS';
|
||||
exports.description = "Interface to show iOS' accessibility samples";
|
||||
exports.description = 'iOS specific Accessibility APIs';
|
||||
exports.examples = [
|
||||
{
|
||||
title: 'Accessibility elements',
|
||||
title: 'iOS Accessibility elements',
|
||||
render(): React.Element<any> {
|
||||
return <AccessibilityIOSExample />;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Check if the screen reader is enabled',
|
||||
render(): React.Element<any> {
|
||||
return <ScreenReaderStatusExample />;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -118,6 +118,10 @@ const ComponentExamples: Array<RNTesterExample> = [
|
||||
];
|
||||
|
||||
const APIExamples: Array<RNTesterExample> = [
|
||||
{
|
||||
key: 'AccessibilityExample',
|
||||
module: require('./AccessibilityExample'),
|
||||
},
|
||||
{
|
||||
key: 'AccessibilityAndroidExample',
|
||||
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
|
||||
|
||||
@@ -171,6 +171,11 @@ const ComponentExamples: Array<RNTesterExample> = [
|
||||
];
|
||||
|
||||
const APIExamples: Array<RNTesterExample> = [
|
||||
{
|
||||
key: 'AccessibilityExample',
|
||||
module: require('./AccessibilityExample'),
|
||||
supportsTVOS: false,
|
||||
},
|
||||
{
|
||||
key: 'AccessibilityIOSExample',
|
||||
module: require('./AccessibilityIOSExample'),
|
||||
|
||||
Reference in New Issue
Block a user