集合视图中带有补充视图的 tvOS 地标

Posted

技术标签:

【中文标题】集合视图中带有补充视图的 tvOS 地标【英文标题】:tvOS Landmarks with Supplementary Views in a collection view Accessibility 【发布时间】:2018-09-17 18:13:25 【问题描述】:

我正在尝试从 Apple 的电影应用程序中复制 Landmark Accessibility 的流程。 我尝试使用带有自定义标题的表格视图和标准标题视图,其中我的单元格内部有一个集合视图,一个集合视图带有一个补充视图,集合视图单元格中有另一个集合视图。

在创建标题视图时,我添加了标题视图标题作为可访问性元素,以尝试遵守 UIAccessibilityContainer:https://developer.apple.com/documentation/uikit/accessibility/uiaccessibilitycontainer。这应该允许我通过公共枚举 UIAccessibilityContainerType 遵守 .landmark 协议。

两者都未能允许地标从一个补充视图或标题的标题移动到下一个补充视图或标题。我最初认为这可能是可访问性中的地标协议的错误,但我注意到其他应用程序也正确使用了地标导航。

带有补充视图的代码集合视图:

struct Content 
let name: String
let color: UIColor

 init(name: String, color: UIColor) 
    self.name = name
    self.color = color
 

class CollecitonViewWithCollectionView: UIViewController 
 let testContent = [Content(name: "AA", color: .red), Content(name: "BB", color: .green), Content(name: "CC", color: .yellow)]

@IBOutlet weak var collectionView: UICollectionView!

override func viewDidLoad() 
    super.viewDidLoad()

    collectionView.accessibilityContainerType = .landmark



extension CollecitonViewWithCollectionView: UICollectionViewDataSource 
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
    return 1


func numberOfSections(in collectionView: UICollectionView) -> Int 
    return 10


func collectionView(_ collectionView: UICollectionView, canFocusItemAt indexPath: IndexPath) -> Bool 
    return false


func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as? CollectionViewCell else 
        return UICollectionViewCell()
    
    cell.content = testContent
    return cell


func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView 
    guard let headerView = collectionView.dequeueReusableSupplementaryView(
        ofKind: UICollectionElementKindSectionHeader,
        withReuseIdentifier: "HeaderView",
        for: indexPath
        ) as? HeaderView

        else 
            return UICollectionReusableView()
    

    return headerView





extension CollecitonViewWithCollectionView: UICollectionViewDelegate 



class InnerCollectionTestCell: UICollectionViewCell 
@IBOutlet weak var testLabel: UILabel!



class CollectionViewCell: UICollectionViewCell, UICollectionViewDelegate, UICollectionViewDataSource 

@IBOutlet weak var collectionView: UICollectionView!

var content: [Content]?

override func awakeFromNib() 
    super.awakeFromNib()
    collectionView.dataSource = self
    collectionView.delegate = self


func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
    return content?.count ?? 0


func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "InnerCollectionTestCell", for: indexPath) as? InnerCollectionTestCell else 
        return UICollectionViewCell()
    
    cell.testLabel.text = content?[indexPath.row].name ?? "Failed"
    cell.backgroundColor = content?[indexPath.row].color ?? .black
    return cell





class HeaderView: UICollectionReusableView 
@IBOutlet weak var titleLabel: UILabel!

使用 headerView 或自定义标题视图编码 TableView:

 class TestCollectionCell: UICollectionViewCell 
    @IBOutlet weak var contentStringLabel: UILabel!



class TestCell: UITableViewCell, UICollectionViewDataSource, UICollectionViewDelegate 
@IBOutlet weak var collectionView: UICollectionView!

var content: [Content]?

override func awakeFromNib() 
    super.awakeFromNib()
    collectionView.dataSource = self
    collectionView.delegate = self


func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
    return content?.count ?? 0


func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TestCollectionCell", for: indexPath) as? TestCollectionCell else 
        return UICollectionViewCell()
    
    cell.backgroundColor = content?[indexPath.row].color ?? .black
    cell.contentStringLabel.text = content?[indexPath.row].name ?? "Zzz"
    return cell





class TableViewWithCollectionView: UIViewController 
 @IBOutlet weak var tableView: UITableView!

 let testContent = [Content(name: "A", color: .red), Content(name: "B", color: .green), Content(name: "C", color: .yellow)]

override func viewDidLoad() 
    super.viewDidLoad()

    let headerNib = UINib(nibName: "TableViewHeaderFooterView", bundle: nil)
     tableView.register(headerNib, forHeaderFooterViewReuseIdentifier:  "TableViewHeaderFooterView")





extension TableViewWithCollectionView: UITableViewDelegate 



extension TableViewWithCollectionView: UITableViewDataSource 

func numberOfSections(in tableView: UITableView) -> Int 
    return 10


func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return 1


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    guard let cell = tableView.dequeueReusableCell(withIdentifier: "TestCell", for: indexPath) as? TestCell else 
        return UITableViewCell()
    
    cell.content = testContent
    return cell


func tableView(_ tableView: UITableView, canFocusRowAt indexPath: IndexPath) -> Bool 
    return false


   /*func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? 
tableView.headerView(forSection: section)?.accessibilityTraits |= UInt64(UIAccessibilityContainerType.landmark.rawValue)

    return "Test Without custom header"
    */

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? 
    let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "TableViewHeaderFooterView") as? TableHeaderFooterView
    headerView?.tableHeaderTitleLabel.text = "TEST with custom header"
    headerView?.accessibilityTraits |= UInt64(UIAccessibilityContainerType.landmark.rawValue)
    return headerView


func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat 
    return 50



我知道对于标题,您需要在 IB 中设置特征或执行以下操作:

//set here because Xcode is not giving me the option in IB
accessibilityTraits |= UIAccessibilityTraitHeader

我会假设地标有这样的方式?

【问题讨论】:

你见过forums.developer.apple.com/thread/69583吗? @Donald 可访问性可以看到标题的元素,问题出在转子上的“地标”设置上。我可以通过浏览单元格中的集合视图项目并到达末尾来滚动到标题,但我不能通过地标专门转到标题。标题似乎也能正常工作。 【参考方案1】:
override var accessibilityLabel: String? 
    get  return titleLabel.accessibilityLabel 
    set 


override var accessibilityTraits: UIAccessibilityTraits 
    get  return UIAccessibilityTraits.header 
    set 


override var accessibilityContainerType: UIAccessibilityContainerType 
    get  return UIAccessibilityContainerType.landmark 
    set 

所以问题是这些值是在可重用标头内设置的,显然这会导致可访问性元素设置正确的问题,而是需要在视图本身上设置它们。将上述代码添加到您的 HeaderView 文件中。

【讨论】:

以上是关于集合视图中带有补充视图的 tvOS 地标的主要内容,如果未能解决你的问题,请参考以下文章

如何在 tvos 应用程序的 collectionview 单元格中的按钮上移动焦点?

焦点引擎不适用于集合视图单元

按钮不可聚焦,因为它遥不可及 - tvOS Swift

如何防止可访问性画外音读出集合视图中选定的单元格位置?

SWIFT:在 TVOS 中退出收集时强制焦点引擎转到按钮

带有约束的嵌套集合视图的意外行为(Swift 4)