textInputlayout中的android对话不一致
我正在尝试使用textInputlayout
和textInputeDittext
textInputlayout 来解决对话访问性事件问题,并且我注意到要读取的内容,很大程度上取决于不同的无关因素。
tl; dr(对于懒惰)
- ,当
textInputlayout/textInputEdittext
组合读取(完成)时,我需要覆盖对话所说的文本,并且当它获得焦点并再次读取内容时(cansn) 't使这项工作,委托被忽略)。 - 我已经测试过:
- 三星S20(对讲)
- OnePlus 9 Android 11(对讲)
- api 31仿真器(我从源中从source 中汇总的对讲),如那里所述。然后将对话apk拖到模拟器中。
- 在大多数情况下,除了某些三星愚蠢™之外,它们的行为都一样。
较长的问题带有详细信息,
我在2022年4月(Bumblebee)的最新Android Studio中创建了一个空白的Android项目。没有撰写UI,没什么特别的。最小API 28减少变量。只是一个空的活动。
我启用了ViewBinding(但没有区别),并确保设置了最新的稳定依赖关系(没有可用的较新版本的“警告”)。
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
布局的
主动脉布局非常简单。在垂直方向上的root ConfaintLayout和(无用的)线度延迟以快速堆叠测试视图,但我只使用一个孩子(在实践中可能会有更多,但删除此ViewGroup没有任何区别,所以我留下了它)。
这是布局的“休息”(删除了简短的包装线胶属性):
<LinearLayout ...
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/inputLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Phone Number"
app:endIconMode="clear_text">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/inputEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="phone" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
这看起来像您想象的。概述的deDittext(在Google Purple中,主题中的默认主要颜色)。 IME设置为电话。
您可以看到的InputType
,我将InputType设置为电话
,因为我对电话号码键盘感兴趣。这为输入电话号码(而不仅仅是数字)提供了一些默认的Android键盘上的小(但潜在有用的)功能。
实际上,将其设置为号码
或电话
在此问题中概述的问题中没有区别。
主要活动?
该活动是空的,只有我在ongreate中添加的代码才存在。
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
// Set a phone number value
binding.inputEditText.setText("628123123") //this is valid in the NL
}
对讲“问题#1”
运行上述,看起来您会期望:
如果您启用对话并阅读此内容,则将其读取为“ 600亿二十八百万。 ..“而不是“六个,二,八,一个,两个...”。这对默认的对讲行为非常愚蠢,因为EditText具有输入类型的电话类型,因此应该将其用作默认的定义操作/事件以及如何创建可访问性节点。没有
,但是有一种方法可以解决这个问题。 BYOAD™:带上您自己的可访问性代表。
好的。
自定义可访问性代表
class MyAccessibilityDelegate(private val layout: TextInputLayout):
TextInputLayout.AccessibilityDelegate(layout) {
override fun onInitializeAccessibilityNodeInfo(host: View, info: AccessibilityNodeInfoCompat) {
super.onInitializeAccessibilityNodeInfo(host, info)
layout.editText?.let {
val content = it.text
info.text = content.toPhoneNumberContentDescription() // More on this below
}
}
}
,您 ,不是EditText :
binding.inputLayout.setTextInputAccessibilityDelegate(
MyAccessibilityDelegate(binding.inputLayout)
)
等待片刻,什么是tophoneNumberContentDescription()
?
只是将手机转换为更可读性的功能。我不会提供代码,因为它是无关紧要的,但是它看起来像:
fun CharSequence?.toPhoneNumberContentDescription() = ...
将其分开:628123123
6 2 8 1,2 3 1,2 3 1 2,3
对话读取数字,以更好的节奏和暂停;无论如何,您都可以将其格式化,这与下一个对话问题无关。
对讲问题#2:焦点。
上面的代表通过对话将电话号码读为单个数字而不是单个数字解决了问题。
如果您熟悉对讲(如果不这样做),则可以“双击以激活/编辑/等”。因此,如果您专注于此EDITTEXT,则可以将屏幕上的任何位置点击以“单击”,以使EditText获得焦点并让IME触发键盘和Android在幕后所做的所有[主要是破碎的]魔法显示键盘并将视图设置为专注。
它还触发了视图的可访问性,因为启用了对话,它现在告诉代表,触发了一个新事件(以可访问性为中心)(除其他事件),而对话又读了其中的内容,以及其自己的一些“编辑文本,blah”等等。
问题是,在双击之后,对话再次将数字读为一个大数字,而不是上面代表提供的修改版本。
这意味着它读为“六百二2八百万...显示键盘”,
如果您用两个手指滑动下一步,您会听到“清除按钮”的描述,如果您向后滑动,那么它将再次读取EditText,但是时间,它正确地读到:“编辑,六,二,八。编辑框电话号码...”很明显“双击要激活”事件/操作正在触发对话,直接从输入文本中读取,忽略委托这应该是格式化的。
我不知道
我可能很累,缺少更多的咖啡,但是我不知道如何覆盖这一事件。代表中的其他方法接收到包含要说的文本的事件,但是该事件中的文字仅 ,所以我必须丢失何处/如何设置这个。
是否有人有能为我提供指导的经验吗?
有趣的不是很有趣的事实,
如果您将任何数量的数字都带有0
,它将被读取为单个数字:0628123123
正确地读取为零,六个,六个,六个,,,,,,,两个,八,一个...
等。
I'm attempting to work around a TalkBack accessibility event issue with a TextInputLayout
and TextInputEditText
, and I've noticed what gets read, greatly depends on different unrelated factors.
tl;dr (for the lazy)
- I need to override the text spoken by TalkBack when a
TextInputLayout/TextInputEditText
combo is read (done) and when it gains focus and the contents are read again for edition (couldn't make this work, delegate is ignored). - I've tested on:
- Samsung S20 (TalkBack)
- OnePlus 9 Android 11 (TalkBack)
- API 31 Emulator with (TalkBack compiled by me from source) as described there. Then dragged TalkBack APK to the emulator.
- In most cases they all behave the same, except some Samsung Stupidity™.
Longer Question With Details
I've created a blank Android project in the latest Android Studio as of April 2022 (Bumblebee). No Compose UI, nothing special. Min API 28 to reduce variables. Just an empty activity.
I enabled ViewBinding (but it made no difference), and made sure the latest stable dependencies are set (no "warnings" of newer versions available).
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
Layout
The Layout for MainActivity is quite simple. A root ConstraintLayout and a (useless) LinearLayout in vertical orientation to quickly stack views for testing, but I'll use only one child (in practice there may be more, but removing this ViewGroup made no difference, so I left it).
Here's the "rest" of the layout (removed the wrapping LinearLayout attributes for brevity):
<LinearLayout ...
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/inputLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Phone Number"
app:endIconMode="clear_text">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/inputEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="phone" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
This looks like you'd imagine. An outlined EditText (in Google Purple, the default primary color in the theme). The IME is set to Phone.
InputType
As you can see, I've set the inputtype to phone
as I am interested in a keyboard for Phone Numbers. This offers a few small (but potentially useful) features on the default Android Keyboard for entering Phone Numbers (and not just digits).
In practice, setting this to number
or phone
made no difference in the problem outlined in this question.
MainActivity?
The Activity is empty, and only the code I added in onCreate exists.
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
// Set a phone number value
binding.inputEditText.setText("628123123") //this is valid in the NL
}
TalkBack "Issue #1"
Running the above, looks like you'd expect:
If you enable TalkBack and read this, it will be read as "six hundred twenty eight million..." and not as "Six, Two, Eight, One, Two...". This is very silly on the default TalkBack behavior, as the EditText has an input type of Phone, it should use that as a default to define the actions/events and how the Accessibility Nodes are created. It doesn't
But there's a way to workaround this. BYOAD™: Bring Your Own Accessibility Delegate.
All right.
A Custom Accessibility Delegate
class MyAccessibilityDelegate(private val layout: TextInputLayout):
TextInputLayout.AccessibilityDelegate(layout) {
override fun onInitializeAccessibilityNodeInfo(host: View, info: AccessibilityNodeInfoCompat) {
super.onInitializeAccessibilityNodeInfo(host, info)
layout.editText?.let {
val content = it.text
info.text = content.toPhoneNumberContentDescription() // More on this below
}
}
}
And you set this in the actual InputLayout, not the EditText:
binding.inputLayout.setTextInputAccessibilityDelegate(
MyAccessibilityDelegate(binding.inputLayout)
)
Wait a moment, what is toPhoneNumberContentDescription()
?
Just a function to transform a phone into something more readable. I'm not going to provide the code because it's irrelevant, but it looks like:
fun CharSequence?.toPhoneNumberContentDescription() = ...
What it does is separates this: 628123123
into 6 2 8 1 , 2 3 1 2 , 3
TalkBack reads the digits with a better cadence and pause; you can format this anyway you want, this is irrelevant to the next TalkBack issue.
TalkBack Issue #2: Focus.
The above Delegate solved the issue with TalkBack reading a phone number as a single number instead of individual digits.
If you're familiar with TalkBack (and if you aren't then you should), you can "double tap to activate/edit/etc". So if you have focus on this EditText, you can double tap anywhere on the screen to "click" on it to let the EditText gain focus and let the IME trigger the keyboard and all the [mostly broken] magic that android does behind the scenes to show your keyboard and set a view as focused.
It also triggers the View's accessibility, as TalkBack is enabled, it now informs the delegate that a new event (accessibility focused) has been triggered (among other events) and TalkBack reads the contents alongside some of its own additions of "edit text, blah blah".
The issue is that after the double tap, TalkBack reads the numbers again as a single big number, not the modified version provided by the above delegate.
This means it reads "six hundred twenty eight million... showing keyboard"
If you the swipe with two fingers to go next, you hear the "clear button" description, if you swipe back, then it reads the EditText again, but this time, it correctly reads: "Editing, six, two, eight.. edit box phone number..." so clearly the "double tap to activate" event/Action is triggering TalkBack to read from the input text directly, ignoring the Delegate that is supposed to format this.
What I couldn't figure out
I may be tired and lacking more coffee, but I couldn't figure out how to override this event. The other methods in the Delegate receive the events which contain the text to be spoken, but the text in that event is read only so I must be missing where/how to set this up.
Does anybody have experience with this that can give me pointers to it?
Fun Not So Fun Fact
If you prefix any number of digits with a 0
, it will be read as individual digits: 0628123123
is correctly read as zero, six, two, eight, one...
etc.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论