diff --git a/AZTabBarController.xcodeproj/project.pbxproj b/AZTabBarController.xcodeproj/project.pbxproj index a5002eb..b57260b 100644 --- a/AZTabBarController.xcodeproj/project.pbxproj +++ b/AZTabBarController.xcodeproj/project.pbxproj @@ -21,6 +21,8 @@ 92BEF46D1DDB72780054FD17 /* AZTabBarController.h in Headers */ = {isa = PBXBuildFile; fileRef = 92BEF4691DDB72780054FD17 /* AZTabBarController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 92BEF46E1DDB72780054FD17 /* AZTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92BEF46A1DDB72780054FD17 /* AZTabBarController.swift */; }; 92BEF4701DDB72780054FD17 /* UIView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92BEF46C1DDB72780054FD17 /* UIView+Extensions.swift */; }; + 9F4F7D3A1F38F6C400492E83 /* AZTabBarController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92C850F41DDA88B900F3C9E3 /* AZTabBarController.framework */; }; + 9F4F7D3B1F38F6C400492E83 /* AZTabBarController.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 92C850F41DDA88B900F3C9E3 /* AZTabBarController.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -33,6 +35,20 @@ }; /* End PBXContainerItemProxy section */ +/* Begin PBXCopyFilesBuildPhase section */ + 9F4F7D3C1F38F6C500492E83 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 9F4F7D3B1F38F6C400492E83 /* AZTabBarController.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ 92A66CBB1DDA8E0B00F792AB /* iOS Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "iOS Example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 92A66CBD1DDA8E0B00F792AB /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -59,6 +75,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 9F4F7D3A1F38F6C400492E83 /* AZTabBarController.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -149,6 +166,7 @@ 92A66CB71DDA8E0B00F792AB /* Sources */, 92A66CB81DDA8E0B00F792AB /* Frameworks */, 92A66CB91DDA8E0B00F792AB /* Resources */, + 9F4F7D3C1F38F6C500492E83 /* Embed Frameworks */, ); buildRules = ( ); @@ -298,6 +316,7 @@ 92A66CCD1DDA8E0B00F792AB /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEVELOPMENT_TEAM = 5MGEMLZRS4; INFOPLIST_FILE = "iOS Example/Info.plist"; @@ -312,6 +331,7 @@ 92A66CCE1DDA8E0B00F792AB /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; DEVELOPMENT_TEAM = 5MGEMLZRS4; INFOPLIST_FILE = "iOS Example/Info.plist"; diff --git a/Source/AZTabBarController.swift b/Source/AZTabBarController.swift index 9f34c50..4499bdf 100644 --- a/Source/AZTabBarController.swift +++ b/Source/AZTabBarController.swift @@ -10,7 +10,11 @@ import Foundation private let defaultHeight: CGFloat = 49 -open class AZTabBarItemView: UIView { +public protocol AZTabBarItemViewAccessibility { + var accessibilityTitle: String { get } +} + +open class AZTabBarItemView: UIView, AZTabBarItemViewAccessibility { public var heightValue: CGFloat? var preferedHeight: CGFloat { return heightValue ?? _preferedHeight @@ -34,6 +38,51 @@ open class AZTabBarItemView: UIView { public static func loadViewFromNib() -> Self { return self.init().az_loadFromNibIfEmbeddedInDifferentNib() } + + open var accessibilityTitle: String { + var title = "" + for view in subviews { + if let label = view as? UILabel, + let text = label.text { + title += "\(text)\n" + } + } + return title + } + + // MARK: - Accessibility + + open override var accessibilityLabel: String? { + get { + if let value = super.accessibilityLabel, + value.characters.count > 0 { + return value + } + return accessibilityTitle + } + set { + super.accessibilityLabel = accessibilityLabel + } + } + + open override var isAccessibilityElement: Bool { + get { + return true + } + set { + super.isAccessibilityElement = newValue + } + } + + open override var accessibilityTraits: UIAccessibilityTraits { + set { + super.accessibilityTraits = accessibilityTraits + } + get { + let value = super.accessibilityTraits + return value | UIAccessibilityTraitButton | (UIAccessibilityTraitSelected * (isSelected ? 1 : 0)) + } + } } public class AZTabBarItem: UITabBarItem { @@ -142,15 +191,22 @@ public class AZTabBarController: UITabBarController { } } - public override func viewDidLayoutSubviews() { - super.viewDidLayoutSubviews() - } - // MARK: - Setup + private var az_itemViewConstraints: [NSLayoutConstraint] = [] + private var az_itemViews: [UIView] = [] + private func az_createViewContainers() { + + NSLayoutConstraint.deactivate(az_itemViewConstraints) + az_itemViewConstraints = [] + + az_itemViews.forEach({ $0.removeFromSuperview() }) + az_itemViews = [] + for (index, item) in az_items.enumerated() { let viewContainer = az_setupView(onItem: item, index: index) + az_itemViews.append(viewContainer) if index == selectedIndexOrZero { item.setSelected(true, animated: false) @@ -159,19 +215,21 @@ public class AZTabBarController: UITabBarController { } tabBar.addSubview(viewContainer) - tabBar.bottomAnchor.constraint(equalTo: viewContainer.bottomAnchor).isActive = true + az_itemViewConstraints.append(tabBar.bottomAnchor.constraint(equalTo: viewContainer.bottomAnchor)) if index > 0 { - az_items[index - 1].containerView.rightAnchor.constraint(equalTo: viewContainer.leftAnchor).isActive = true - az_items[index - 1].containerView.widthAnchor.constraint(equalTo: viewContainer.widthAnchor).isActive = true + az_itemViewConstraints.append(az_items[index - 1].containerView.rightAnchor.constraint(equalTo: viewContainer.leftAnchor)) + az_itemViewConstraints.append(az_items[index - 1].containerView.widthAnchor.constraint(equalTo: viewContainer.widthAnchor)) } } if let firstItem = az_items.first, let lastItem = az_items.last { - tabBar.leftAnchor.constraint(equalTo: firstItem.containerView.leftAnchor).isActive = true - tabBar.rightAnchor.constraint(equalTo: lastItem.containerView.rightAnchor).isActive = true + az_itemViewConstraints.append(tabBar.leftAnchor.constraint(equalTo: firstItem.containerView.leftAnchor)) + az_itemViewConstraints.append(tabBar.rightAnchor.constraint(equalTo: lastItem.containerView.rightAnchor)) } + NSLayoutConstraint.activate(az_itemViewConstraints) + tabBar.alpha = 1 tabBar.shadowImage = UIImage() tabBar.backgroundImage = UIImage() @@ -209,7 +267,8 @@ public class AZTabBarController: UITabBarController { } var selectedIndexOrZero: Int { - return selectedIndex < (viewControllers?.count ?? 0) ? selectedIndex : 0 + let numberOfElements = viewControllers?.count ?? 0 + return selectedIndex < numberOfElements ? selectedIndex : 0 } public override var selectedIndex: Int { diff --git a/iOS Example/Base.lproj/Main.storyboard b/iOS Example/Base.lproj/Main.storyboard index cc1cc2f..6304c81 100644 --- a/iOS Example/Base.lproj/Main.storyboard +++ b/iOS Example/Base.lproj/Main.storyboard @@ -1,10 +1,10 @@ - + - + @@ -200,7 +200,7 @@ - + diff --git a/iOS Example/FashionTabBarItem.swift b/iOS Example/FashionTabBarItem.swift index 3c08fca..5d47f71 100644 --- a/iOS Example/FashionTabBarItem.swift +++ b/iOS Example/FashionTabBarItem.swift @@ -17,6 +17,8 @@ class FashionTabBarItem: AZTabBarItemView { @IBOutlet weak var bottomLabel: UILabel! override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + topLabel.text = selected ? "Selected" : "Unselected" backgroundColor = selected ? UIColor.green : UIColor.lightGray @@ -24,6 +26,10 @@ class FashionTabBarItem: AZTabBarItemView { imageView.shake(coefficient: 1, duration: 0.35) } } + + override var accessibilityTitle: String { + return bottomLabel.text ?? super.accessibilityTitle + } } diff --git a/iOS Example/MiddleTabBarItem.swift b/iOS Example/MiddleTabBarItem.swift index 824caaf..c8a5c9a 100644 --- a/iOS Example/MiddleTabBarItem.swift +++ b/iOS Example/MiddleTabBarItem.swift @@ -14,6 +14,8 @@ class MiddleTabBarItem: AZTabBarItemView { @IBOutlet weak var textLabel: UILabel! override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + textLabel.textColor = selected ? UIColor.black : UIColor.black.withAlphaComponent(0.6) backgroundColor = selected ? UIColor.green : UIColor.lightGray }