AnimatableTabBarController.swift 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. //
  2. // Created by phimage on 11/04/2017.
  3. // Copyright © 2017 IBAnimatable. All rights reserved.
  4. //
  5. import UIKit
  6. open class AnimatableTabBarController: UITabBarController, TransitionAnimatable {
  7. // MARK: - TransitionAnimatable
  8. @IBInspectable var _transitionAnimationType: String? {
  9. didSet {
  10. if let _transitionAnimationType = _transitionAnimationType {
  11. transitionAnimationType = TransitionAnimationType(string: _transitionAnimationType)
  12. }
  13. }
  14. }
  15. open var transitionAnimationType: TransitionAnimationType = .none {
  16. didSet {
  17. configureNavigationControllerDelegate()
  18. }
  19. }
  20. @IBInspectable open var transitionDuration: Double = .nan {
  21. didSet {
  22. configureNavigationControllerDelegate()
  23. }
  24. }
  25. open var interactiveGestureType: InteractiveGestureType = .none {
  26. didSet {
  27. configureNavigationControllerDelegate()
  28. }
  29. }
  30. @IBInspectable var _interactiveGestureType: String? {
  31. didSet {
  32. if let _interactiveGestureType = _interactiveGestureType {
  33. interactiveGestureType = InteractiveGestureType(string: _interactiveGestureType)
  34. }
  35. }
  36. }
  37. // MARK: - UITabBarDelegate
  38. open override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
  39. guard let animatable = item as? (UITabBarItem & Animatable),
  40. let tabBarButton = tabBar.view(for: item) else {
  41. return
  42. }
  43. // Animate the children image view
  44. if let imageView = tabBarButton.subviews.first(where: { $0 is UIImageView }) {
  45. animatable.animate(view: imageView)
  46. }
  47. }
  48. // MARK: - Private
  49. // Must have a property to keep the reference alive because `UITabBarController.delegate` is `weak`
  50. fileprivate var navigator: Navigator?
  51. fileprivate func configureNavigationControllerDelegate() {
  52. if case .none = transitionAnimationType {
  53. navigator = nil
  54. delegate = nil
  55. return
  56. }
  57. var duration = transitionDuration
  58. // Set the default duration for transition
  59. if transitionDuration.isNaN {
  60. duration = defaultTransitionDuration
  61. }
  62. if case .none = interactiveGestureType {
  63. navigator = Navigator(transitionAnimationType: transitionAnimationType, transitionDuration: duration)
  64. } else {
  65. navigator = Navigator(transitionAnimationType: transitionAnimationType,
  66. transitionDuration: duration,
  67. interactiveGestureType: interactiveGestureType)
  68. }
  69. delegate = navigator
  70. }
  71. }
  72. private extension UITabBar {
  73. func view(for item: UITabBarItem) -> UIControl? {
  74. // return item.value(forKeyPath: "view") as? UIControl // apple could not allow that
  75. #if swift(>=4.2)
  76. guard let items = self.items,
  77. let index = items.firstIndex(of: item) else {
  78. return nil
  79. }
  80. #else
  81. guard let items = self.items,
  82. let index = items.index(of: item) else {
  83. return nil
  84. }
  85. #endif
  86. // get all buttons
  87. // 1/ filter on control, not safe if apple add a new control in bar
  88. let controls = self.subviews.filter { $0 is UIControl }
  89. // 2/ filter on name, not safe if button class change
  90. // let controls = self.subviews.filter { String(describing: type(of: $0 )) == "UITabBarButton" }
  91. guard index < controls.count else {
  92. // item could be not in tab bar (see "More")
  93. return nil
  94. }
  95. return controls[index] as? UIControl
  96. }
  97. }