collection 视图中具有补充视图的 tvOS 地标
tvOS Landmarks with Supplementary Views in a collection view Accessibility
我正在尝试从 Apple 的电影应用程序复制 Landmark Accessibility 的流程。
我尝试使用带有自定义 header 的 table 视图和标准 header 视图,我的单元格内部有一个 collection 视图和一个 collection 视图collection 视图单元格内的另一个 collection 视图的补充视图。
我在创建视图时将 header 视图标题添加为可访问性元素以尝试遵守 UIAccessibilityContainer:https://developer.apple.com/documentation/uikit/accessibility/uiaccessibilitycontainer。这应该允许我通过 public 枚举 UIAccessibilityContainerType 来遵守 .landmark 协议。
两者都不允许地标从一个补充视图或 header 的标题移动到下一个补充视图或 header。我最初认为这可能是辅助功能中 Landmarks 协议的错误,但我注意到其他应用程序也正确使用了 Landmark 导航。
带有补充视图的代码 CollectionView:
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!
}
使用 header 视图或自定义 header 视图对 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
我想 Landmarks 有这样的方法吗?
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 {}
}
所以问题是这些值是在可重复使用的内部设置的 header,显然这会导致正确设置可访问性元素的问题,而需要在视图本身上设置它们。将以上代码添加到您的 HeaderView 文件中。
我正在尝试从 Apple 的电影应用程序复制 Landmark Accessibility 的流程。 我尝试使用带有自定义 header 的 table 视图和标准 header 视图,我的单元格内部有一个 collection 视图和一个 collection 视图collection 视图单元格内的另一个 collection 视图的补充视图。
我在创建视图时将 header 视图标题添加为可访问性元素以尝试遵守 UIAccessibilityContainer:https://developer.apple.com/documentation/uikit/accessibility/uiaccessibilitycontainer。这应该允许我通过 public 枚举 UIAccessibilityContainerType 来遵守 .landmark 协议。
两者都不允许地标从一个补充视图或 header 的标题移动到下一个补充视图或 header。我最初认为这可能是辅助功能中 Landmarks 协议的错误,但我注意到其他应用程序也正确使用了 Landmark 导航。
带有补充视图的代码 CollectionView:
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!
}
使用 header 视图或自定义 header 视图对 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
我想 Landmarks 有这样的方法吗?
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 {}
}
所以问题是这些值是在可重复使用的内部设置的 header,显然这会导致正确设置可访问性元素的问题,而需要在视图本身上设置它们。将以上代码添加到您的 HeaderView 文件中。