android tts_让对话tts跨越Android辅助功能

android tts

Originally shared on my personal blog post.

最初在我的 个人博客文章 上分享

A great talk from the Google IO 2019 called “Demystifying Android Accessibility Development” mentions that when designing apps, we often miss to account for the users with accessibility needs. Users with accessibility needs won’t interact with the app directly, but instead they will use tools such as the Android Accessibility Suite (includes Talkback and Switch Access). The user will interact with the Accessibility service and then the service will interact with the app.

Google IO 2019的一篇精彩演讲称为“ 揭开Android可访问性开发的神秘面纱 ”,提到在设计应用程序时,我们经常会忽略考虑到具有可访问性需求的用户。 具有可访问性需求的用户不会直接与该应用进行交互,而是会使用诸如Android Accessibility Suite (包括对讲和切换访问)之类的工具。 用户将与辅助功能服务交互,然后该服务将与应用程序交互。

Accessibility services need information on what the screen has or shows to be able to provide the correct contextual information to the user or to be able to navigate through the app. An example of that information can be provided using Content Descriptions.

辅助功能服务需要有关屏幕上具有或显示的内容的信息,以便能够向用户提供正确的上下文信息或能够浏览应用程序。 可以使用“ 内容描述”提供该信息的示例。

In this blog post we’ll talk about Spans in Android and how to enrich Spannables to provide a better UX to users with accessibility needs.

在此博客文章中,我们将讨论Android中的Spans以及如何丰富Spannable s以便为具有可访问性需求的用户提供更好的UX。

Spans are powerful markup objects that you can use to style text at a character or paragraph level.

跨度是功能强大的标记对象,可用于在字符或段落级别设置文本样式。

With Spans we can change the text color of a substring or have a link-clickable part within a string, or even different size substrings. Sky is the limit 🚀

使用Spans,我们可以更改子字符串的文本颜色,或者在字符串中甚至具有不同大小的子字符串中具有可链接单击的部分。 天空是极限🚀

In this post, we’ll specifically talk about TtsSpan.

在本文中,我们将专门讨论TtsSpan

跨度 (TtsSpan)

A TtsSpan can provide metadata for a Spannable. The metadata will be supplied to Text-To-Speech Engines such as Talkback.

TtsSpan可以提供Spannable的元数据。 元数据将提供给文本语音转换引擎,例如Talkback

This span comes with several builders and each builder helps building metadata for a different type. The types supported by the builders are:

该范围包含多个构建器,每个构建器都可以帮助构建不同类型的元数据。 建设者支持的类型是:

To demonstrate their benefits, we’ll explore the following types:

为了展示它们的好处,我们将探索以下类型:

  • TtsSpan.TYPE_DATE

    TtsSpan.TYPE_DATE

  • TtsSpan.TYPE_MEASURE

    TtsSpan.TYPE_MEASURE

  • TtsSpan.TYPE_TIME

    TtsSpan.TYPE_TIME

  • TtsSpan.TYPE_ELECTRONIC

    TtsSpan.TYPE_ELECTRONIC

演示简介 (Brief introduction to demo)

The demo application has a list of items. Each item is duplicated, one without TtsSpan and one with TtsSpan to highlight the differences.

演示应用程序具有项目列表。 每一项都是重复的,一项没有TtsSpan,另一项有TtsSpan以突出显示差异。

Image for post

When an item is clicked, we pass the Spannable (with or without TtsSpan) to the TextToSpeech service to output the metadata.

单击一个项目时,我们将Spannable(带有或不带有TtsSpan)传递给TextToSpeech服务以输出元数据。

验证 (Verification)

To verify that the metadata are supplied to the TextToSpeech engines correctly, we could do the following:

为了验证元数据是否正确提供给TextToSpeech引擎,我们可以执行以下操作:

  1. Supply the spannables to the TextToSpeech.speak method which will output the data

    将spannable提供给TextToSpeech。 会输出数据的语音方法

  2. Turn on Talkback and navigate the demo using the service

    开启“话语提示”并使用该服务浏览演示

The demo videos use the first point + Live Caption to verify and present you the output.

演示视频使用第一点+ 实时字幕来验证并向您展示输出。

建立清单 (Building the list)

The list is built using RecyclerView with TtsItem classes. Each item has a title, a caption and a nullable type of TtsSpan (if null then no TtsSpan is built).

该列表是使用RecyclerView和TtsItem类构建的。 每个项目都有一个TtsSpan的标题 ,标题和可为null的类型(如果为null,则不构建任何TtsSpan)。

data class TtsItem(
val title: String,
val caption: String,
private val ttsSpanType: String?
) {
var id: Int = 0 fun toSpannable(): SpannableString? { ... }
}
Image for post

To produce the different TtsItem, we have a data factory called DummyDataFactory .

为了产生不同的TtsItem,我们有一个名为DummyDataFactory的数据工厂。

object DummyDataFactory {    fun getListOfTtsItem(): List<TtsItem> = listOf(
TtsItem("18/04/2020", "Date without TTSSpan", null),
TtsItem("18/04/2020", "Date with TtsSpan.DateBuilder", TtsSpan.TYPE_DATE), TtsItem("5 meter", "Measure without TTSSpan", null),
TtsItem("5 meter", "Measure with TTSSpan", TtsSpan.TYPE_MEASURE), TtsItem("14:00", "Time without TTSSpan", null),
TtsItem("14:00", "Time with TTSSpan", TtsSpan.TYPE_TIME), TtsItem("admin:123456789", "Password without TTSSpan", null),
TtsItem("admin:123456789", "Password with TTSSpan", TtsSpan.TYPE_ELECTRONIC)
).also { list ->
list.forEachIndexed { index, ttsItem -> ttsItem.id = index }
}
}

从TtsItem探索toSpannable() (Explore toSpannable() from TtsItem)

Disclaimer: Please note that some of the code shown below is for demonstration purposes only and mapping strings to TtsSpan most likely won’t work like that in real life projects.

免责声明 :请注意,下面显示的某些代码仅用于演示目的,并且将字符串映射到TtsSpan很有可能在现实项目中无法正常工作。

Note: Have a look at the captions to see the difference with and without TtsSpan.

注意:查看字幕以了解使用和不使用TtsSpan的区别。

TtsSpan.TYPE_DATE (TtsSpan.TYPE_DATE)

val calendar = Calendar.getInstance()
calendar.time = simpleDataFormat.parse(title)
?: throw IllegalStateException("Not expected null Date")TtsSpan.DateBuilder()
.setWeekday(calendar.get(Calendar.DAY_OF_WEEK))
.setDay(calendar.get(Calendar.DAY_OF_MONTH))
.setMonth(calendar.get(Calendar.MONTH))
.setYear(calendar.get(Calendar.YEAR))

The above code block will take a String date, parse it into a Date object which is then supplied to a Calendar. Then the Calendar object is used to extract different information that would be useful to TtsSpan.DateBuilder().

上面的代码块将使用String日期,将其解析为Date对象,然后将其提供给Calendar。 然后,将Calendar对象用于提取对TtsSpan.DateBuilder()有用的不同信息。

Demonstration of the Date TtsSpan Builder
  • Caption without TtsSpan:18 slash 04 slash 2020

    没有TtsSpan的标题:18斜杠04斜杠2020

  • Caption with TtsSpan:Sunday the 18th of April 2020

    TtsSpan的标题:2020年4月18日,星期日

TtsSpan.TYPE_MEASURE (TtsSpan.TYPE_MEASURE)

val number = digitsPattern.find(title)?.value // extracts digits
val unit = stringPattern.find(title)?.value // extracts string
TtsSpan.MeasureBuilder()
.setNumber(number)
.setUnit(unit)

The above code block will extract the digits from the string which will be treated as the number and then extract the text from the string which will be treated as the Measurement unit. All the extracted data are supplied to the TtsSpan.MeasureBuilder.

上面的代码块将从字符串中提取数字,将其视为数字 ,然后从字符串中提取文本,将其视为度量单位。 所有提取的数据都将提供给TtsSpan.MeasureBuilder

Demonstration of the Measure Unit builder with TtsSpan
  • Caption without TtsSpan:5 metre

    没有TtsSpan的标题:5米

  • Caption with TtsSpan:5 metres

    TtsSpan的标题:5米

As you can see the metadata helps identify whether the measurement is singular or plural.

如您所见,元数据有助于确定度量是单数还是复数。

TtsSpan.TYPE_TIME (TtsSpan.TYPE_TIME)

val hours = title.split(":")[0]
val minutes = title.split(":")[1]
TtsSpan.TimeBuilder()
.setHours(hours.toInt())
.setMinutes(minutes.toInt())

The above code block builds metadata needed for time. It simply extracts hours and minutes from string and supplies them to the TtsSpan.TimeBuilder().

上面的代码块构建了时间所需的元数据。 它只是从字符串中提取小时和分钟,并将它们提供给TtsSpan.TimeBuilder()

Demonstration of the Time Builder with TtsSpan
  • Caption without TtsSpan:14 colon zero zero

    没有TtsSpan的标题:14冒号零零

  • Caption with TtsSpan:14 hundred

    TtsSpan的标题:14百

TtsSpan.TYPE_ELECTRONIC (TtsSpan.TYPE_ELECTRONIC)

This particular type can be used to build several “electronic” metadata. In our example we’ll build metadata for a username and password.

此特定类型可用于构建多个“电子”元数据。 在我们的示例中,我们将为用户名和密码构建元数据。

val username = title.split(":")[0]
val password = title.split(":")[1]
TtsSpan.ElectronicBuilder()
.setPassword(password)
.setUsername(username)

The above code block uses the TtsSpan.ElectronicBuilder to build the metadata. The first part of the string is treated as the username and the second part as the password.

上面的代码块使用TtsSpan.ElectronicBuilder构建元数据。 字符串的第一部分被视为用户名,第二部分被视为密码。

Demonstration of the Electronic Builder with TtsSpan
  • Caption without TtsSpan:admin 123 million 456 thousands 7 hundred and 89

    没有TtsSpan的标题:管理员1.23亿456千7百89

  • Caption with TtsSpan:admin passoword 1 2 3 4 5 6 7 8 9

    带TtsSpan的标题:admin password 1 2 3 4 5 6 7 8 9

The above example is my favourite as it demonstrates how powerful the Text-to-Speech engine can be with the correct metadata.

上面的示例是我的最爱,因为它演示了正确的元数据,文本到语音引擎的功能多么强大。

结论 (Conclusion)

Providing rich UX is important, and we need to make sure that our apps are accessible for all users. We have seen some examples on how to add some metadata in apps so that Text to Speech services provide contextual information.

提供丰富的UX很重要,我们需要确保所有用户都可以访问我们的应用程序。 我们已经看到了一些有关如何在应用程序中添加一些元数据的示例,以便“文本到语音”服务提供上下文信息。

➡ All the above examples can be found at the sample project on Github.

above以上所有示例都可以 在Github 上的 示例项目中 找到

Feel free to ping me on Twitter or check out my personal blog.

随时在Twitter上 ping我或查看我的个人博客

Till next time! 👋

直到下一次! 👋

翻译自: https://proandroiddev.com/lets-talk-tts-spans-in-android-accessibility-fc79c57754eb

android tts

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值