如何正确设置 RN AccessibilityInfo setAccessibilityFocus

Posted

技术标签:

【中文标题】如何正确设置 RN AccessibilityInfo setAccessibilityFocus【英文标题】:How to set properly RN AccessibilityInfo setAccessibilityFocus 【发布时间】:2019-08-01 22:56:20 【问题描述】:

React Native App,ios 测试。 期望的行为: 在 TextInput 中输入无效值并单击提交按钮。屏幕阅读器外壳发音错误,焦点外壳返回到 textInput。设置焦点外壳不打开键盘。

实施中的问题: 焦点返回到 textInput 似乎是在可访问性标签更新为错误消息之前。旧无障碍标签的屏幕阅读器发音。 如果在 Voice Over 的发音后触摸 textInput,则带有错误消息的更新的辅助功能标签是发音。

该代码也可在世博小吃中找到, snack

import * as React from 'react';
import  AccessibilityInfo, TextInput, Button, Text, View, StyleSheet  from 'react-native';
import Constants from 'expo-constants';
import AssetExample from './components/AssetExample';

import  Card  from 'react-native-paper';

const errorBtn = "Click to simulate invalid text input";
const clearBtn = "Click to clear the error";
const errorLabel = "Wrong Number has being typed, try again";
const clearLabel = "Phone Number";
const description = 
"Enable Voice Over, If Error hapens on textInput, screen reader shell pronounce the error message and set focus to the textInput where the error happend"
const placeholder = "Type 10 digit phone number"

export default class App extends React.Component 
  state = 
           error: false,
           text: "", 
           buttonTitle: errorBtn
           
errorMsg= () => this.setState(error: true)
clearMsg= () => this.setState(error: false)

onPress = () => 
  const TextInputNativeTag =   
                    this
                      .textOInputRef
                      ._inputRef
                      ._nativeTag
  if (this.state.buttonTitle == errorBtn) 
    this.errorMsg();
  if (this.state.buttonTitle == clearBtn) 
    this.clearMsg();
  if (this.textOInputRef) 
    AccessibilityInfo
    .setAccessibilityFocus(TextInputNativeTag);

  this.state.buttonTitle == errorBtn &&
  this.setState(buttonTitle:clearBtn);

  this.state.buttonTitle == clearBtn && 
  this.setState(buttonTitle:errorBtn) ;
  
  render() 
    return (
    <View>
      <View >
        <Text accessibilityRole='header' 
              style=styles.header
        >
          Accessabiity Focuse Tester
        </Text>
        <Text style=styles.paragraph>
          description
        </Text>
      </View>
        <View style=styles.body>
          <View style=styles.sectionContainer           >
            <Text 
              accessibilityRole='header' 
              style=styles.sectionTitle
            >
              Accessability Label
            </Text>
            <Text style=
              styles.sectionDescription
            >
              this.state.error 
                ? errorLabel 
                : clearLabel 
              
            </Text>
          </View>

          <View style=
            styles.sectionContainer
          >
            <TextInput
                ref=r => 
                  this.textOInputRef = r
                
                style=
                  height: 40, 
                   borderColor: 'gray', 
                   borderWidth: 1
                
                accessibilityLabel=
                  this.state.error 
                   ? errorLabel 
                   : clearLabel 
                
                underlineColorandroid=
                  "transparent"
                keyboardType="numeric"
                returnKeyType="done"
                onChangeText=
                  text => 
                    this.setState(text)
                
                placeholder=placeholder
                placeholderTextColor=
                  "rgb(143,143,143)"
                value=this.state.text
              />
          </View>

          <View style=styles.sectionContainer>
            <Button 
              onPress=this.onPress 
              title=this.state.buttonTitle
              color="#841584"
              accessibilityLabel=this
                                  .state
                                  .buttonTitle
            />
          </View>
        </View>
    </View>
  ); 
 


const styles = StyleSheet.create(
  header: 
    margin: 24,
    fontSize: 18,
    textAlign: 'center',
    fontWeight: 'bold',
  ,
  paragraph: 
    margin: 24,
    fontSize: 18,
    textAlign: 'center',
  ,
  body: 
    backgroundColor: '#fff',
  ,
  sectionContainer: 
    marginTop: 32,
    paddingHorizontal: 24,
  ,
  sectionTitle: 
    fontSize: 24,
    fontWeight: '600',
    color: '#000',
  ,
  sectionDescription: 
    marginTop: 8,
    fontSize: 18,
    fontWeight: '400',
  ,
);

【问题讨论】:

【参考方案1】:

当按下按钮时,屏幕阅读器会在 onPress 方法的操作过程中读取按钮标签。因此,需要提前安排渲染时间。 此外,需要在标签更新为新值后将 setfocus 调度到 textInput。 以下是代码和snack

import * as React from 'react';
import  AccessibilityInfo, TextInput, TouchableWithoutFeedback, Text, View, StyleSheet  from 'react-native';

const errorBtn = "Click to simulate invalid text input";
const clearBtn = "Click to clear the error";
const errorLabel = "Wrong Number has being typed, try again";
const clearLabel = "Phone Number";
const description = 
"Enable Voice Over, If Error hapens on textInput, screen reader shell pronounce the error message and set focus to the textInput where the error happend"
const placeholder = "Type 10 digit phone number"

export default class App extends React.Component 
state =   
           error: false,
           text: "", 
           buttonTitle: errorBtn
           
label=clearLabel;
accessabilityMsg=null;
textInputRef=null;

onPress = () => 
  const textInput = this.textInputRef && this.textInputRef._inputRef._nativeTag;
  if (this.state.buttonTitle == errorBtn) 
    console.log('onPress set label & state to error');
    setTimeout(()=>
      this.setState(error: true,buttonTitle:clearBtn);
      setTimeout(()=>textInput && AccessibilityInfo.setAccessibilityFocus(textInput),500);
    ,6000);
    this.label=errorLabel;
   else 
    console.log('onPress set label & state to normal') 
    this.setState(error: false,buttonTitle:errorBtn);
    this.label=clearLabel;
  


  render() 
    return (
    <View >
      <View >
        <Text accessibilityRole='header' 
              style=styles.header
        >
          Accessabiity Focus Tester
        </Text>
        <Text style=styles.paragraph>
          description
        </Text>
      </View>
        <View style=styles.body>
          <View style=styles.sectionContainer           >
            <Text 
              accessibilityRole='header' 
              style=styles.sectionTitle
            >
              Accessability Label
            </Text>
            <Text style=
              styles.sectionDescription
            >
              this.label
            </Text>
          </View>

          <View style=
            styles.sectionContainer
          >
            <TextInput
                ref=r => 
                  this.textInputRef = r
                
                style=
                  height: 40, 
                   borderColor: 'gray', 
                   borderWidth: 1
                
                accessibilityLabel=this.label
                underlineColorAndroid=
                  "transparent"
                keyboardType="numeric"
                returnKeyType="done"
                onChangeText=
                  text => 
                    this.setState(text)
                
                placeholder=placeholder
                placeholderTextColor=
                  "rgb(143,143,143)"
                value=this.state.text
              />
          </View>

          <View style=styles.button>
            <TouchableWithoutFeedback
              accessible
              accessibilityRole='button'
              accessibilityLabel=this.state.buttonTitle
              onPress=this.onPress
            >
              <Text> this.state.buttonTitle </Text>
            </TouchableWithoutFeedback>
          </View>
        </View>
    </View>
  ); 
 


const styles = StyleSheet.create(
  header: 
    margin: 24,
    fontSize: 18,
    textAlign: 'center',
    fontWeight: 'bold',
  ,
  paragraph: 
    margin: 24,
    fontSize: 18,
    textAlign: 'center',
  ,
  body: 
    backgroundColor: '#fff',
  ,
  sectionContainer: 
    marginTop: 32,
    paddingHorizontal: 24,
  ,
  sectionTitle: 
    fontSize: 24,
    fontWeight: '600',
    color: '#000',
  ,
  sectionDescription: 
    marginTop: 8,
    fontSize: 18,
    fontWeight: '400',
  ,
  button: 
    margin: 24,
    alignItems: 'center',
    backgroundColor: '#DDDDDD',
    padding: 10,
    borderColor: '#000',
    borderWidth: 1
  ,
);

最后,还是没有完成任务。 我们不能设计基于 setTimout 的应用程序。 仍然需要找到更好的方法。 感谢您的任何评论和帖子。

【讨论】:

您找到更好的解决方案了吗?我也最终使用了 setTimeout,但如果组件在事件触发之前卸载,则会导致一系列问题。

以上是关于如何正确设置 RN AccessibilityInfo setAccessibilityFocus的主要内容,如果未能解决你的问题,请参考以下文章

RN 如何给页面传参数

RN正确获取安卓屏幕高度

rn运行在安卓真机上怎么reload

带有 Typescript 和样式化组件的 RN FlatList

RN设置Image图片固定在底部位置

React Native mapStateToProps未设置state + Redux