- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在为名为 Swordy Quest 的 iOS 游戏构建完全可访问性:
https://apps.apple.com/us/app/swordy-quest-an-rpg-adventure/id1446641513
正如您从上面链接的屏幕截图中看到的,我创建了一张 map ,其中包含 50x50 个单独的 UIView,每个 UIView 上都有一个 UIButton,所有这些都位于 UIScrollView 上。关闭 VoiceOver 后,整个应用程序(包括 map 部分)都可以正常工作 - 尽管 map 加载有时会有点慢。当我打开 VoiceOver 时,整个应用程序响应良好,除了 map 部分,它变得非常滞后 - 在我的 iPhone 7 上几乎无法播放(比如用旧手机测试最糟糕的用户体验)。
如果打开 VoiceOver,我曾尝试删除图像细节,但这根本没有区别。这让我认为滞后是由于 50 x 50 UIViews 所有这些都添加了可访问性标签。如果单个 UIViewController 上有太多可访问的标签,VoiceOver 是否会开始严重滞后?
有谁知道一种巧妙的方法来解决这个问题?我想知道是否有一种聪明的方法可以关闭 AccessibilityLabels,除非 UIView/UIButton 位于 UIScrollView 的可见部分?
最佳答案
您不应一次实例化和渲染 2500 个 View 。
现代设备可以很好地处理它,但它仍然会影响性能和内存使用,应该避免。
支持 VoiceOver 只是表面上这种不好的做法。
此处使用的正确工具是 UICollectionView。只有可见 View 才会加载到内存中,这显着限制了性能影响。
您可以轻松实现任何类型的自定义布局,包括您需要的 x/y 可滚动瓷砖 map 。
请参阅以下最小实现以帮助您入门。您可以将代码复制到新创建的 Xcode 项目的 AppDelegate.swift 文件中,以根据您的需要进行调整。
// 1. create new Xcode project
// 2. delete all swift files except AppDelegate
// 3. delete storyboard
// 4. delete references to storyboard and scene from info.plist
// 5. copy the following code to AppDelegate
import UIKit
// boilerplate
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
let layout = MapLayout(columnCount: 50, itemSize: 50)!
self.window?.rootViewController = ViewController(collectionViewLayout: layout)
self.window?.makeKeyAndVisible()
return true
}
}
class MapLayout: UICollectionViewLayout {
let columnCount: Int
let itemSize: CGFloat
var layoutAttributesCache = Dictionary<IndexPath, UICollectionViewLayoutAttributes>()
init?(columnCount: Int, itemSize: CGFloat) {
guard columnCount > 0 else { return nil }
self.columnCount = columnCount
self.itemSize = itemSize
super.init()
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
override var collectionViewContentSize: CGSize {
let itemCount = self.collectionView?.numberOfItems(inSection: 0) ?? 0
let width = CGFloat(min(itemCount, self.columnCount)) * itemSize
let height = ceil(CGFloat(itemCount / self.columnCount)) * itemSize
return CGSize(width: width, height: height)
}
// the interesting part: here the layout is calculated
override func prepare() {
let itemCount = self.collectionView?.numberOfItems(inSection: 0) ?? 0
for index in 0..<itemCount {
let xIndex = index % self.columnCount
let yIndex = Int( Double(index / self.columnCount) )
let xPos = CGFloat(xIndex) * self.itemSize
let yPos = CGFloat(yIndex) * self.itemSize
let cellAttributes = UICollectionViewLayoutAttributes(forCellWith: IndexPath(item: index, section: 0))
cellAttributes.frame = CGRect(x: xPos, y: yPos, width: self.itemSize, height: self.itemSize)
self.layoutAttributesCache[cellAttributes.indexPath] = cellAttributes
}
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
layoutAttributesCache.values.filter { rect.intersects($0.frame) }
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
self.layoutAttributesCache[indexPath]!
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { false }
}
// boilerplate
class ViewController: UICollectionViewController {
var columnCount: Int { (self.collectionViewLayout as! MapLayout).columnCount }
var rowCount: Int { columnCount }
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
}
override func numberOfSections(in collectionView: UICollectionView) -> Int { 1 }
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { rowCount * columnCount }
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
let fancyColor = UIColor(hue: CGFloat((indexPath.row % columnCount))/CGFloat(columnCount), saturation: 1, brightness: 1 - floor( Double(indexPath.row) / Double( columnCount) ) / Double(rowCount), alpha: 1).cgColor
cell.layer.borderColor = fancyColor
cell.layer.borderWidth = 2
return cell
}
}
结果应该是这样的:
关于swift - 带有许多 subview 的 VoiceOver 在屏幕上非常滞后/缓慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68075185/
我有一个自定义单选按钮,按钮有一个彩色的更大的圆圈。它是使用 CSS 实现的,如 http://webdesign.tutsplus.com/articles/quick-tip-easy-css3-
我试图让 VoiceOver 说出 HTML span 元素中指定文本内容以外的内容: 1:02a 考虑我可能希望 VoiceOver 说出完整文本的情况。 当我添加 aria-label 属性时,V
我有以下标题 ADD MONEY 它被 VoiceOver 读取为 a-d-d money 而如果我将文本更改为小写,它将正确读取为“加钱”。你有什么建议吗?我已经尝试使用 aria-labelled
我有一个按钮可以切换显示的标签: class ViewController: UIViewController { @IBOutlet weak var label: UILabel!
VoiceOver 焦点不会超出导航项目。我正在向右滑动,但焦点被困在导航项的最后一个元素上。也许它应该移动到 ViewController View 的第一个元素。我已经设置了accessibili
我有一个 UIButton 子类 ACTLanguageButton,它实际上只是做了一些自定义 UI 更改,以便我可以重用该样式。在子类中,我有以下与可访问性相关的代码: - (BOOL)isAcc
我正在为我的 iOS 应用程序添加辅助功能。我看到一个特定的情况,当我点击具有 isAccessibilityElement = false 的 UIView,并且它的所有祖先 View 也是 isA
我正在编写一个应用程序,它使用 touchesBegan/Moved/etc 来跟踪手势并将其绘制在屏幕上。启用 VoiceOver 后,当我在绘图区域上双击时,无论实际点击的位置如何,第一次触摸总是
当 voiceOver 开启时,我正在 iPhone 上尝试双指滑动手势(使用两根手指在屏幕上画一个 Z),但它不起作用,而默认后退手势在没有 voiceOver 的情况下工作。 我已经创建了一个自定
打开 VoiceOver 后,当用户用三个手指滑动滚动时,会播报当前页面,例如:“第 1 页,共 3 页”。然而,这些公告并不总是正确的。 下面的代码创建了一个 ScrollView 并用三个标签填充
我在包含强/强调标记的 UIWebView 中有一些 HTML。我想强制 VoiceOver 连续阅读而不是在句子中间暂停,因为有强标记或强调标记。例如: This text reads conti
如何让 VoiceOver 滚动到 UIScrollView 中屏幕外的元素。 我有一个 UIScrollView。这里面是一个包含许多 subview 的 UIView。在这些 subview 中是
我正在构建一个将在信息亭模式下运行的应用程序,作为覆盖主页按钮的灌输的一部分。 我想让用户能够在需要时打开 VoiceOver。 是否可以通过编程方式执行此操作? 编辑澄清 我不想只打开语音合成器,而
iOS 8.x VoiceOver 宣布已禁用的按钮变暗而不是禁用。有没有办法以编程方式让 VoiceOver 说“已禁用”而不是“变暗”? 最佳答案 有很多方法可以做你想做的事,但你绝对不应该使用它
我在 iPhone 应用程序中有一个字段包含“1.2 m”。 VoiceOver 会将其读作“1 点 2 米”。我有点惊讶 VoiceOver 足够聪明,可以理解单位。 但是,我有一个不同的字段,其中
我目前无法将 VoiceOver 的焦点设置为特定标签。根据 Apple 的开发者网站 (https://developer.apple.com/library/ios/featuredarticle
我有一个自定义键盘应用程序,目前正在处理语音支持更新,但删除(退格)按钮有问题。 我的键盘现在的工作方式与苹果默认键盘完全一样,在“触摸打字”模式下带有旁白。当用户点击 w、a、s,然后点击空格时,V
我终于确定了一个在录制视频时使 UIImagePickerController 崩溃的错误。启用 iPhone 的 VoiceOver 辅助功能设置后,录音机在调用 presentModalViewC
如果标签上的文本发生变化,是否可以使用 iPhone 上的 VoiceOver 来宣布更新后的文本? 这类似于 ARIA 中的实时区域。 谢谢。 最佳答案 您可以使用 VoiceOver 朗读您喜欢的
我使用带有空标题和图像的 NSButton,并且无法通过 VoiceOver 访问它。但是当我设置标题时(VoiceOver 似乎使用标题),NSButton 尝试显示它。 我认为应该有一种简单的方法
我是一名优秀的程序员,十分优秀!