- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个 String
有多个链接。我正在使用 SpannableText
并且除了可访问性回话外,它运行良好。
有没有办法让链接可访问?
最佳答案
创建一个如下所示的类
package com.go.disney.disneycruise.util
import android.content.Context
import android.graphics.Rect
import android.os.Bundle
import android.text.Layout
import android.text.Spanned
import android.text.style.ClickableSpan
import android.view.accessibility.AccessibilityEvent
import android.widget.TextView
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
import androidx.customview.widget.ExploreByTouchHelper
import com.disney.wdpro.dlog.DLog
import com.disney.wdpro.support.accessibility.ContentDescriptionBuilder
import kotlin.math.max
import kotlin.math.min
/**
* An accessibility delegate that allows [ClickableSpan] to be focused and
* clicked by accessibility services.
*
* @author arun.muraleedharan.
*/
class LinkAccessibilityHelper(
private val linkTextView: TextView,
private val context: Context,
private val linkAccessibilityId: String? = null
) : ExploreByTouchHelper(linkTextView) {
private val viewRect = Rect()
override fun getVirtualViewAt(x: Float, y: Float): Int {
val text = linkTextView.text
if (text is Spanned) {
val offset = getOffsetForPosition(linkTextView, x, y)
val linkSpans = text.getSpans(offset, offset, ClickableSpan::class.java)
if (linkSpans.size == 1) {
val linkSpan = linkSpans[0]
return text.getSpanStart(linkSpan)
}
}
return INVALID_ID
}
override fun getVisibleVirtualViews(virtualViewIds: MutableList<Int>) {
val text = linkTextView.text
if (text is Spanned) {
val linkSpans = text.getSpans(0, text.length, ClickableSpan::class.java)
for (span in linkSpans) {
virtualViewIds.add(text.getSpanStart(span))
}
}
}
override fun onPopulateEventForVirtualView(virtualViewId: Int, event: AccessibilityEvent) {
val span = getSpanForOffset(virtualViewId)
if (span != null) {
val spannedTextAccessibility = getTextForSpan(span).toString() + LINK
event.contentDescription = spannedTextAccessibility
} else {
DLog.e(TAG, "LinkSpan is null for offset: $virtualViewId")
event.contentDescription = linkTextView.text
}
}
override fun onPopulateNodeForVirtualView(
virtualViewId: Int,
info: AccessibilityNodeInfoCompat
) {
linkAccessibilityId?.let { info.viewIdResourceName = it }
val span = getSpanForOffset(virtualViewId)
if (span != null) {
val contentDescriptionBuilder = ContentDescriptionBuilder(
context
)
contentDescriptionBuilder.append(getTextForSpan(span).toString())
contentDescriptionBuilder.appendWithSeparator(LINK)
info.contentDescription = contentDescriptionBuilder.toString()
} else {
DLog.e(TAG, "LinkSpan is null for offset: $virtualViewId")
info.contentDescription = linkTextView.text
}
info.isFocusable = true
info.isClickable = true
getBoundsForSpan(span, viewRect)
if (viewRect.isEmpty) {
DLog.e(TAG, "LinkSpan bounds is empty for: $virtualViewId")
viewRect[0, 0, 1] = 1
}
info.setBoundsInParent(viewRect)
info.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK)
}
override fun onPerformActionForVirtualView(
virtualViewId: Int,
action: Int,
arguments: Bundle?
): Boolean {
if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) {
val span = getSpanForOffset(virtualViewId)
if (span != null) {
span.onClick(linkTextView)
return true
} else {
DLog.e(TAG, "LinkSpan is null for offset: $virtualViewId")
}
}
return false
}
private fun getSpanForOffset(offset: Int): ClickableSpan? {
val text = linkTextView.text
if (text is Spanned) {
val spans = text.getSpans(offset, offset, ClickableSpan::class.java)
if (spans.size == 1) {
return spans[0]
}
}
return null
}
private fun getTextForSpan(span: ClickableSpan): CharSequence {
val text = linkTextView.text
if (text is Spanned) {
return text.subSequence(
text.getSpanStart(span),
text.getSpanEnd(span)
)
}
return text
}
// Find the bounds of a span. If it spans multiple lines, it will only return the bounds for the
// section on the first line.
private fun getBoundsForSpan(span: ClickableSpan?, outRect: Rect): Rect {
val text = linkTextView.text
outRect.setEmpty()
if (text is Spanned) {
val layout = linkTextView.layout
if (layout != null) {
val spanStart = text.getSpanStart(span)
val spanEnd = text.getSpanEnd(span)
val xStart = layout.getPrimaryHorizontal(spanStart)
val xEnd = layout.getPrimaryHorizontal(spanEnd)
val lineStart = layout.getLineForOffset(spanStart)
val lineEnd = layout.getLineForOffset(spanEnd)
layout.getLineBounds(lineStart, outRect)
if (lineEnd == lineStart) {
// If the span is on a single line, adjust both the left and right bounds
// so outrect is exactly bounding the span.
outRect.left = min(xStart, xEnd).toInt()
outRect.right = max(xStart, xEnd).toInt()
} else {
// If the span wraps across multiple lines, only use the first line (as returned
// by layout.getLineBounds above), and adjust the "start" of outrect to where
// the span starts, leaving the "end" of outrect at the end of the line.
// ("start" being left for LTR, and right for RTL)
if (layout.getParagraphDirection(lineStart) == Layout.DIR_RIGHT_TO_LEFT) {
outRect.right = xStart.toInt()
} else {
outRect.left = xStart.toInt()
}
}
// Offset for padding
outRect.offset(linkTextView.totalPaddingLeft, linkTextView.totalPaddingTop)
}
}
return outRect
}
companion object {
private const val TAG = "LinkAccessibilityHelper"
const val LINK = "link."
// Compat implementation of TextView#getOffsetForPosition().
private fun getOffsetForPosition(view: TextView, x: Float, y: Float): Int {
if (view.layout == null) {
return -1
}
val line = getLineAtCoordinate(view, y)
return getOffsetAtCoordinate(view, line, x)
}
private fun convertToLocalHorizontalCoordinate(view: TextView, x: Float): Float {
var coordinateX = x
coordinateX -= view.totalPaddingLeft.toFloat()
// Clamp the position to inside of the view.
coordinateX = max(0.0f, coordinateX)
coordinateX = min((view.width - view.totalPaddingRight - 1).toFloat(), coordinateX)
coordinateX += view.scrollX.toFloat()
return coordinateX
}
private fun getLineAtCoordinate(view: TextView, y: Float): Int {
var coordinateY = y
coordinateY -= view.totalPaddingTop.toFloat()
// Clamp the position to inside of the view.
coordinateY = max(0.0f, coordinateY)
coordinateY = min((view.height - view.totalPaddingBottom - 1).toFloat(), coordinateY)
coordinateY += view.scrollY.toFloat()
return view.layout.getLineForVertical(coordinateY.toInt())
}
private fun getOffsetAtCoordinate(view: TextView, line: Int, x: Float): Int {
var coordinateX = x
coordinateX = convertToLocalHorizontalCoordinate(view, coordinateX)
return view.layout.getOffsetForHorizontal(line, coordinateX)
}
}
}
之后像下面那样实现它
ViewCompat.setAccessibilityDelegate(
textView, LinkAccessibilityHelper(
textView, context, "linkId"
)
)
关于android - 有什么方法可以将可跨文本集中在 Android 中以实现可访问性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41595791/
我想做一个系统,用户可以上传和下载文件。系统将具有一个集中的地形,但在很大程度上依赖于节点将相关数据通过中心节点传输给其他节点我不希望对等端保存整个文件,而是希望它们保存整个数据集的一个压缩的加密部分
我正在 Riverpod Auth 流程样板应用程序中工作。 我想对所有异步功能甚至登录和注销使用通用加载屏幕。目前,如果 Appstate 加载我显示加载屏幕,我有 AppState 提供程序。它可
我有一个 functions.php 文件,其中包括以下功能: function head() { global $brand, $brandName, $logo, $slogan, $si
我有下一个 html 代码 ... 我想选择随机的 div 数组来向它们添加一个事件类,因为我使用这个 jquery 代码 function randOrder() { return
多年来,我创建并调整了一组NAnt脚本以执行完整的项目构建。主脚本采用一个应用程序端点(例如,一个Web应用程序项目),并从源代码控制中对其进行完整的构建。脚本已预先配置了与构建输出位置,源代码控制地
我希望我的 jQuery 插件在 $(window) 选择上调用时表现不同。如何检查 window 是否在集合中?到目前为止我的尝试: >>> $(window) == $(window) false
考虑到我们有 let existingSet = $(); 如何通过 jQuery 将 newElements 添加到该集合中? existingSet = existingSet.add(newEl
我需要在 priority_queue 中保存一个整数集合。但是我需要能够删除这些整数中的一个,即使它不是我容器的第一个元素。我无法使用 std::priority_queue。我选择使用一个集合来根
对于我的网站,我一直在尝试集中所有内容以便在移动设备上显示: http://m.bachatdeals.com 我在移动设备上打开网站后,内容下方有很多空间,我必须捏住 zoon 才能阅读,如何删除下
我计划为我的剑道验证器制定一些自定义规则,并希望在所有验证器之间共享。在我的验证器代码中,我有: rules: { bothorblank: function (input) {
这是我的函数,用于测试两个点 x 和 y 在 MAX_ITERATION 255 之后是否在 mandelbrot 集合中。如果不在,它应该返回 0,如果在,则返回 1。 int isMandelbr
致力于从移动设备扩展到桌面设备的简单网站布局。一切都按预期工作,但由于某种原因,我的 float div 没有集中放置。我已经完成了正常工作,但这次不适合我?有什么想法吗? 这是我的 CSS: /*
我的“div”元素有一个相对宽度,它不是绝对的,所以我不能使用精确的数字来集中。一个不错的解决方案是使用“display: inline-block”: body { text-align:
目前我拥有的所有类都处理它们自己的导入。使用一个典型的例子: [ImportMany] private Lazy[] someOfMyInterfaces { get; set; } public M
我有一个类定义: class Question: title = "" answer = "" def __init__(self, title, answer):
我正在尝试将一个对象 Point2D 插入到一个 Point2D 集合中,但我做不到,似乎该集合适用于 int 和 char 但不适用于对象。 我需要帮助来了解如何将对象插入到集合中???假设我想按
我的应用上有一些弹出窗口,它是全屏的,代码如下: content.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
我们有一个多模块 Quarkus 项目,带有一个公共(public)库和多个应用程序。在通用的 lib 中,我们有各种缓存用于所有应用。 我们希望不必在每个应用程序的所有配置文件中配置保留和容量。 有
这个问题在这里已经有了答案: Nested facets in ggplot2 spanning groups (2 个回答) 去年关闭。 我在 ggplot 中创建了一个图表里面有两个变量 face
我无法集中v-radio-group。这是我得到的:
我是一名优秀的程序员,十分优秀!