Updated accessibility, add addressed review comments
This commit is contained in:
parent
3a064c914c
commit
024194e7e5
@ -16,6 +16,7 @@
|
|||||||
5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */; };
|
5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */; };
|
||||||
5FC35BE328D51405004EBEAC /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC35BE228D51405004EBEAC /* Button.swift */; };
|
5FC35BE328D51405004EBEAC /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC35BE228D51405004EBEAC /* Button.swift */; };
|
||||||
7115BD3C2B84C0C200E0A610 /* TileContainerChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */; };
|
7115BD3C2B84C0C200E0A610 /* TileContainerChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */; };
|
||||||
|
71ACE89C2BA0451200FB6ADC /* PaginationCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71ACE89B2BA0451200FB6ADC /* PaginationCollectionView.swift */; };
|
||||||
71B23C2D2B91FA690027F7D9 /* Pagination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71B23C2C2B91FA690027F7D9 /* Pagination.swift */; };
|
71B23C2D2B91FA690027F7D9 /* Pagination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71B23C2C2B91FA690027F7D9 /* Pagination.swift */; };
|
||||||
71B5FCBB2B95A0CA00269BCC /* PaginationChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 71B5FCBA2B95A0CA00269BCC /* PaginationChangeLog.txt */; };
|
71B5FCBB2B95A0CA00269BCC /* PaginationChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 71B5FCBA2B95A0CA00269BCC /* PaginationChangeLog.txt */; };
|
||||||
71BFA70A2B7F70E6000DCE33 /* DropShadowable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */; };
|
71BFA70A2B7F70E6000DCE33 /* DropShadowable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */; };
|
||||||
@ -192,6 +193,7 @@
|
|||||||
5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = "<group>"; };
|
5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = "<group>"; };
|
||||||
5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = "<group>"; };
|
5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = "<group>"; };
|
||||||
7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TileContainerChangeLog.txt; sourceTree = "<group>"; };
|
7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TileContainerChangeLog.txt; sourceTree = "<group>"; };
|
||||||
|
71ACE89B2BA0451200FB6ADC /* PaginationCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationCollectionView.swift; sourceTree = "<group>"; };
|
||||||
71B23C2C2B91FA690027F7D9 /* Pagination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pagination.swift; sourceTree = "<group>"; };
|
71B23C2C2B91FA690027F7D9 /* Pagination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pagination.swift; sourceTree = "<group>"; };
|
||||||
71B5FCBA2B95A0CA00269BCC /* PaginationChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = PaginationChangeLog.txt; sourceTree = "<group>"; };
|
71B5FCBA2B95A0CA00269BCC /* PaginationChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = PaginationChangeLog.txt; sourceTree = "<group>"; };
|
||||||
71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropShadowable.swift; sourceTree = "<group>"; };
|
71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropShadowable.swift; sourceTree = "<group>"; };
|
||||||
@ -404,6 +406,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
71B23C2C2B91FA690027F7D9 /* Pagination.swift */,
|
71B23C2C2B91FA690027F7D9 /* Pagination.swift */,
|
||||||
|
71ACE89B2BA0451200FB6ADC /* PaginationCollectionView.swift */,
|
||||||
71FC86D92B96F44C00700965 /* PaginationButton.swift */,
|
71FC86D92B96F44C00700965 /* PaginationButton.swift */,
|
||||||
71FC86DB2B96F4C800700965 /* PaginationCellItem.swift */,
|
71FC86DB2B96F4C800700965 /* PaginationCellItem.swift */,
|
||||||
71FC86E32B9841AC00700965 /* PaginationFlowLayout.swift */,
|
71FC86E32B9841AC00700965 /* PaginationFlowLayout.swift */,
|
||||||
@ -1056,6 +1059,7 @@
|
|||||||
EAC925842911C63100091998 /* Colorable.swift in Sources */,
|
EAC925842911C63100091998 /* Colorable.swift in Sources */,
|
||||||
EAB5FEF5292D371F00998C17 /* ButtonBase.swift in Sources */,
|
EAB5FEF5292D371F00998C17 /* ButtonBase.swift in Sources */,
|
||||||
EA978EC5291D6AFE00ACC883 /* AnyLabelAttribute.swift in Sources */,
|
EA978EC5291D6AFE00ACC883 /* AnyLabelAttribute.swift in Sources */,
|
||||||
|
71ACE89C2BA0451200FB6ADC /* PaginationCollectionView.swift in Sources */,
|
||||||
EAC71A1F2A2E173D00E47A9F /* RadioButton.swift in Sources */,
|
EAC71A1F2A2E173D00E47A9F /* RadioButton.swift in Sources */,
|
||||||
EA33622C2891E73B0071C351 /* FontProtocol.swift in Sources */,
|
EA33622C2891E73B0071C351 /* FontProtocol.swift in Sources */,
|
||||||
EA596ABD2A16B4EC00300C4B /* Tab.swift in Sources */,
|
EA596ABD2A16B4EC00300C4B /* Tab.swift in Sources */,
|
||||||
|
|||||||
@ -21,24 +21,16 @@ open class Pagination: View {
|
|||||||
///Selected page index
|
///Selected page index
|
||||||
private var _selectedPageIndex: Int = 0
|
private var _selectedPageIndex: Int = 0
|
||||||
///Custom flow layout defined for the Pagination
|
///Custom flow layout defined for the Pagination
|
||||||
private let flowLayout = PaginationFlowLayout()
|
private var flowLayout: PaginationFlowLayout {
|
||||||
|
guard let flowLayout = collectionContainerView.collectionView.collectionViewLayout as? PaginationFlowLayout else { fatalError("Flow layout should be PaginationFlowLayout class") }
|
||||||
|
return flowLayout
|
||||||
|
}
|
||||||
///A root view for the pagination
|
///A root view for the pagination
|
||||||
private let containerView: View = View().with {
|
private let containerView: View = View().with {
|
||||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||||
}
|
}
|
||||||
///Collectionview to render pagination indexes
|
///Container view to hold collectionview to render pagination indexes
|
||||||
private lazy var collectionView: UICollectionView = {
|
private let collectionContainerView = PaginationCollectionView()
|
||||||
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
|
|
||||||
collectionView.isScrollEnabled = false
|
|
||||||
collectionView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
collectionView.delegate = self
|
|
||||||
collectionView.dataSource = self
|
|
||||||
collectionView.showsHorizontalScrollIndicator = false
|
|
||||||
collectionView.showsVerticalScrollIndicator = false
|
|
||||||
collectionView.register(PaginationCellItem.self, forCellWithReuseIdentifier: PaginationCellItem.identifier)
|
|
||||||
collectionView.backgroundColor = .clear
|
|
||||||
return collectionView
|
|
||||||
}()
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Public Properties
|
// MARK: - Public Properties
|
||||||
@ -86,24 +78,32 @@ open class Pagination: View {
|
|||||||
super.initialSetup()
|
super.initialSetup()
|
||||||
|
|
||||||
addSubview(containerView)
|
addSubview(containerView)
|
||||||
containerView.pinToSuperView()
|
containerView
|
||||||
containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: 288).activate()
|
.pinTop()
|
||||||
|
.pinBottom()
|
||||||
|
containerView.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor).activate()
|
||||||
|
trailingAnchor.constraint(greaterThanOrEqualTo: containerView.trailingAnchor).activate()
|
||||||
|
containerView.centerXAnchor.constraint(equalTo: centerXAnchor).activate()
|
||||||
|
containerView.widthAnchor.constraint(equalToConstant: 288).activate()
|
||||||
containerView.heightAnchor.constraint(equalToConstant: 44).activate()
|
containerView.heightAnchor.constraint(equalToConstant: 44).activate()
|
||||||
containerView.addSubview(previousButton)
|
containerView.addSubview(previousButton)
|
||||||
containerView.addSubview(collectionView)
|
containerView.addSubview(collectionContainerView)
|
||||||
containerView.addSubview(nextButton)
|
containerView.addSubview(nextButton)
|
||||||
|
|
||||||
previousButton
|
previousButton
|
||||||
.pinTop()
|
.pinTop()
|
||||||
.pinBottom()
|
.pinBottom()
|
||||||
.pinLeading()
|
.pinLeading()
|
||||||
previousButton.trailingAnchor.constraint(greaterThanOrEqualTo: collectionView.leadingAnchor).activate()
|
|
||||||
collectionView.heightAnchor.constraint(equalToConstant: VDSLayout.Spacing.space4X.value).activate()
|
previousButton.trailingAnchor.constraint(greaterThanOrEqualTo: collectionContainerView.leadingAnchor).activate()
|
||||||
collectionView.centerYAnchor.constraint(equalTo: centerYAnchor).activate()
|
collectionContainerView.heightAnchor.constraint(equalToConstant: VDSLayout.Spacing.space4X.value).activate()
|
||||||
collectionView.centerXAnchor.constraint(equalTo: centerXAnchor).activate()
|
collectionContainerView.centerYAnchor.constraint(equalTo: centerYAnchor).activate()
|
||||||
collectionView.trailingAnchor.constraint(greaterThanOrEqualTo: nextButton.leadingAnchor).activate()
|
collectionContainerView.centerXAnchor.constraint(equalTo: centerXAnchor).activate()
|
||||||
collectionViewWidthAnchor = collectionView.widthAnchor.constraint(equalToConstant: 92)
|
collectionContainerView.trailingAnchor.constraint(greaterThanOrEqualTo: nextButton.leadingAnchor).activate()
|
||||||
|
collectionViewWidthAnchor = collectionContainerView.widthAnchor.constraint(equalToConstant: 92)
|
||||||
collectionViewWidthAnchor?.activate()
|
collectionViewWidthAnchor?.activate()
|
||||||
|
collectionContainerView.collectionView.delegate = self
|
||||||
|
collectionContainerView.collectionView.dataSource = self
|
||||||
|
|
||||||
nextButton
|
nextButton
|
||||||
.pinTop()
|
.pinTop()
|
||||||
@ -117,8 +117,24 @@ open class Pagination: View {
|
|||||||
flowLayout.$collectionViewWidth
|
flowLayout.$collectionViewWidth
|
||||||
.receive(on: RunLoop.main)
|
.receive(on: RunLoop.main)
|
||||||
.sink { [weak self] value in
|
.sink { [weak self] value in
|
||||||
self?.collectionViewWidthAnchor?.constant = value
|
self?.collectionViewWidthAnchor?.constant = value //As cell width is dynamic i.e cell may contain 2 or 3 or 4 charcters. Make sure that all the visible cells are displayed.
|
||||||
}.store(in: &subscribers)
|
}.store(in: &subscribers)
|
||||||
|
collectionContainerView.onAccessibilityIncrement = { [weak self] in
|
||||||
|
guard let self else { return }
|
||||||
|
self.selectedPage = max(0, self.selectedPage + 1)
|
||||||
|
}
|
||||||
|
collectionContainerView.onAccessibilityDecrement = { [weak self] in
|
||||||
|
guard let self else { return }
|
||||||
|
self.selectedPage = max(0, self.selectedPage - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///Updating the accessiblity values i.e elements, label, value other items for the component.
|
||||||
|
open override func updateAccessibility() {
|
||||||
|
super.updateAccessibility()
|
||||||
|
accessibilityElements = [previousButton, collectionContainerView, nextButton]
|
||||||
|
collectionContainerView.accessibilityLabel = "Pagination containing \(total) pages"
|
||||||
|
collectionContainerView.accessibilityValue = "Page \(selectedPage) of \(total) selected"
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used to make changes to the View based off a change events or from local properties.
|
/// Used to make changes to the View based off a change events or from local properties.
|
||||||
@ -126,7 +142,7 @@ open class Pagination: View {
|
|||||||
super.updateView()
|
super.updateView()
|
||||||
nextButton.surface = surface
|
nextButton.surface = surface
|
||||||
previousButton.surface = surface
|
previousButton.surface = surface
|
||||||
collectionView.reloadData()
|
collectionContainerView.collectionView.reloadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -137,21 +153,25 @@ open class Pagination: View {
|
|||||||
let isNextAction = sender == nextButton
|
let isNextAction = sender == nextButton
|
||||||
_selectedPageIndex = if isNextAction { _selectedPageIndex + 1 } else { _selectedPageIndex - 1 }
|
_selectedPageIndex = if isNextAction { _selectedPageIndex + 1 } else { _selectedPageIndex - 1 }
|
||||||
updateSelection()
|
updateSelection()
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { [weak self] in
|
||||||
|
guard let self else { return }
|
||||||
|
UIAccessibility.post(notification: .announcement, argument: "Page \(self.selectedPage) of \(self.total) selected")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///Refreshing the UI based on the selected page
|
///Refreshing the UI based on the selected page
|
||||||
private func updateSelection() {
|
private func updateSelection() {
|
||||||
guard _selectedPageIndex < total else { return }
|
guard _selectedPageIndex < total else { return }
|
||||||
//Need to make selected page as second element so scrolling previous index of the selected page to left
|
//Need to make selected page as second element so scrolling previous index of the selected page to left
|
||||||
collectionView.scrollToItem(at: IndexPath(row: max(_selectedPageIndex - 1, 0), section: 0), at: .left, animated: false)
|
collectionContainerView.collectionView.scrollToItem(at: IndexPath(row: max(_selectedPageIndex - 1, 0), section: 0), at: .left, animated: false)
|
||||||
previousButton.isHidden = _selectedPageIndex == 0
|
previousButton.isHidden = _selectedPageIndex == 0
|
||||||
nextButton.isHidden = _selectedPageIndex == total - 1
|
nextButton.isHidden = _selectedPageIndex == total - 1
|
||||||
collectionView.reloadData()
|
collectionContainerView.collectionView.reloadData()
|
||||||
verifyIfMaxDigitChanged()
|
verifyIfMaxDigitChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
///Identifying if there is any change in the digits of upcoming page
|
///Identifying if there is any change in the digits of upcoming page
|
||||||
func verifyIfMaxDigitChanged() {
|
private func verifyIfMaxDigitChanged() {
|
||||||
let upperLimitPage = _selectedPageIndex + flowLayout.maxNumberOfColumns
|
let upperLimitPage = _selectedPageIndex + flowLayout.maxNumberOfColumns
|
||||||
let upperLimitDigits = upperLimitPage.digitCount //future value digits
|
let upperLimitDigits = upperLimitPage.digitCount //future value digits
|
||||||
switch (flowLayout.numberOfColumns, upperLimitDigits) {
|
switch (flowLayout.numberOfColumns, upperLimitDigits) {
|
||||||
@ -163,9 +183,9 @@ open class Pagination: View {
|
|||||||
if upperLimitDigits != flowLayout.upperLimitDigits {
|
if upperLimitDigits != flowLayout.upperLimitDigits {
|
||||||
flowLayout.upperLimitDigits = upperLimitDigits
|
flowLayout.upperLimitDigits = upperLimitDigits
|
||||||
flowLayout.invalidateLayout()
|
flowLayout.invalidateLayout()
|
||||||
collectionView.reloadData()
|
collectionContainerView.collectionView.reloadData()
|
||||||
//Need to make selected page as second element so scrolling previous index of the selected page to left
|
//Need to make selected page as second element so scrolling previous index of the selected page to left
|
||||||
collectionView.scrollToItem(at: IndexPath(row: max(_selectedPageIndex - 1, 0), section: 0), at: .left, animated: false)
|
collectionContainerView.collectionView.scrollToItem(at: IndexPath(row: max(_selectedPageIndex - 1, 0), section: 0), at: .left, animated: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,6 +23,7 @@ final class PaginationCellItem: UICollectionViewCell {
|
|||||||
private var indexLabel: Label = Label().with {
|
private var indexLabel: Label = Label().with {
|
||||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||||
$0.textAlignment = .center
|
$0.textAlignment = .center
|
||||||
|
$0.isAccessibilityElement = false
|
||||||
$0.numberOfLines = 1
|
$0.numberOfLines = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
66
VDS/Components/Pagination/PaginationCollectionView.swift
Normal file
66
VDS/Components/Pagination/PaginationCollectionView.swift
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
//
|
||||||
|
// PaginationCollectionView.swift
|
||||||
|
// VDS
|
||||||
|
//
|
||||||
|
// Created by Bandaru, Krishna Kishore on 12/03/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
///PaginationCollectionView is a container view that holds collectionview for displaying page indexes
|
||||||
|
final class PaginationCollectionView: View {
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Internal Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
///Notifies when accessibility increment is happend when user swipes up
|
||||||
|
var onAccessibilityIncrement: (() -> Void)?
|
||||||
|
///Notifies when accessibility decrement is happend when user swipes down
|
||||||
|
var onAccessibilityDecrement: (() -> Void)?
|
||||||
|
///Collectionview to render pagination indexes
|
||||||
|
lazy var collectionView: UICollectionView = {
|
||||||
|
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
|
||||||
|
collectionView.isScrollEnabled = false
|
||||||
|
collectionView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
collectionView.showsHorizontalScrollIndicator = false
|
||||||
|
collectionView.showsVerticalScrollIndicator = false
|
||||||
|
collectionView.isAccessibilityElement = true
|
||||||
|
collectionView.register(PaginationCellItem.self, forCellWithReuseIdentifier: PaginationCellItem.identifier)
|
||||||
|
collectionView.backgroundColor = .clear
|
||||||
|
return collectionView
|
||||||
|
}()
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Private Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
///Custom flow layout defined for the Pagination
|
||||||
|
private let flowLayout = PaginationFlowLayout()
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Overrides
|
||||||
|
//--------------------------------------------------
|
||||||
|
///Accessibilty traits for the Pagination view
|
||||||
|
override var accessibilityTraits: UIAccessibilityTraits {
|
||||||
|
get { [.adjustable] }
|
||||||
|
set { }
|
||||||
|
}
|
||||||
|
|
||||||
|
///Accessibilty increment
|
||||||
|
override func accessibilityIncrement() {
|
||||||
|
onAccessibilityIncrement?()
|
||||||
|
}
|
||||||
|
|
||||||
|
///Accessibilty decrement
|
||||||
|
override func accessibilityDecrement() {
|
||||||
|
onAccessibilityDecrement?()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Executed on initialization for this View.
|
||||||
|
override func setup() {
|
||||||
|
super.setup()
|
||||||
|
addSubview(collectionView)
|
||||||
|
collectionView.pinToSuperView()
|
||||||
|
isAccessibilityElement = true
|
||||||
|
accessibilityElements = [collectionView]
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user