UIViewController.swift 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. //
  2. // UIViewController.swift
  3. // Mastodon
  4. //
  5. // Created by Cirno MainasuK on 2021-1-27.
  6. //
  7. import UIKit
  8. extension UIViewController {
  9. /// Returns the top most view controller from given view controller's stack.
  10. var topMost: UIViewController? {
  11. // presented view controller
  12. if let presentedViewController = presentedViewController {
  13. return presentedViewController.topMost
  14. }
  15. // UITabBarController
  16. if let tabBarController = self as? UITabBarController,
  17. let selectedViewController = tabBarController.selectedViewController {
  18. return selectedViewController.topMost
  19. }
  20. // UINavigationController
  21. if let navigationController = self as? UINavigationController,
  22. let visibleViewController = navigationController.visibleViewController {
  23. return visibleViewController.topMost
  24. }
  25. // UIPageController
  26. if let pageViewController = self as? UIPageViewController,
  27. pageViewController.viewControllers?.count == 1 {
  28. return pageViewController.viewControllers?.first?.topMost ?? self
  29. }
  30. // child view controller
  31. for subview in self.view?.subviews ?? [] {
  32. if let childViewController = subview.next as? UIViewController {
  33. return childViewController.topMost
  34. }
  35. }
  36. return self
  37. }
  38. }
  39. extension UIViewController {
  40. func viewController<T: UIViewController>(of type: T.Type) -> T? {
  41. if let viewController = self as? T {
  42. return viewController
  43. }
  44. // UITabBarController
  45. if let tabBarController = self as? UITabBarController {
  46. for tab in tabBarController.viewControllers ?? [] {
  47. if let viewController = tab.viewController(of: type) {
  48. return viewController
  49. }
  50. }
  51. }
  52. // UINavigationController
  53. if let navigationController = self as? UINavigationController {
  54. for page in navigationController.viewControllers {
  55. if let viewController = page.viewController(of: type) {
  56. return viewController
  57. }
  58. }
  59. }
  60. // UIPageController
  61. if let pageViewController = self as? UIPageViewController {
  62. for page in pageViewController.viewControllers ?? [] {
  63. if let viewController = page.viewController(of: type) {
  64. return viewController
  65. }
  66. }
  67. }
  68. // child view controller
  69. for subview in self.view?.subviews ?? [] {
  70. if let childViewController = subview.next as? UIViewController,
  71. let viewController = childViewController.viewController(of: type) {
  72. return viewController
  73. }
  74. }
  75. return nil
  76. }
  77. }
  78. extension UIViewController {
  79. /// https://bluelemonbits.com/2018/08/26/inserting-cells-at-the-top-of-a-uitableview-with-no-scrolling/
  80. static func topVisibleTableViewCellIndexPath(in tableView: UITableView, navigationBar: UINavigationBar) -> IndexPath? {
  81. let navigationBarRectInTableView = tableView.convert(navigationBar.bounds, from: navigationBar)
  82. let navigationBarMaxYPosition = CGPoint(x: 0, y: navigationBarRectInTableView.origin.y + navigationBarRectInTableView.size.height + 1) // +1pt for UIKit cell locate
  83. let mostTopVisiableIndexPath = tableView.indexPathForRow(at: navigationBarMaxYPosition)
  84. return mostTopVisiableIndexPath
  85. }
  86. static func tableViewCellOriginOffsetToWindowTop(in tableView: UITableView, at indexPath: IndexPath, navigationBar: UINavigationBar) -> CGFloat {
  87. let rectForTopRow = tableView.rectForRow(at: indexPath)
  88. let navigationBarRectInTableView = tableView.convert(navigationBar.bounds, from: navigationBar)
  89. let navigationBarMaxYPosition = CGPoint(x: 0, y: navigationBarRectInTableView.origin.y + navigationBarRectInTableView.size.height) // without +1pt
  90. let differenceBetweenTopRowAndNavigationBar = rectForTopRow.origin.y - navigationBarMaxYPosition.y
  91. return differenceBetweenTopRowAndNavigationBar
  92. }
  93. }
  94. extension UIViewController {
  95. /// https://stackoverflow.com/a/27301207/3797903
  96. var isModal: Bool {
  97. let presentingIsModal = presentingViewController != nil
  98. let presentingIsNavigation = navigationController != nil && navigationController?.presentingViewController?.presentedViewController == navigationController
  99. let presentingIsTabBar = tabBarController?.presentingViewController is UITabBarController
  100. return presentingIsModal || presentingIsNavigation || presentingIsTabBar
  101. }
  102. }