UIScrollView+Empty.swift 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. //
  2. // UIScrollView+Empty.swift
  3. // HDEmptyViewDemo
  4. //
  5. // Created by liuyi on 2018/5/18.
  6. // Copyright © 2018年 liuyi. All rights reserved.
  7. //
  8. import UIKit
  9. import Foundation
  10. extension UIScrollView {
  11. struct RuntimeKey {
  12. static let kEmptyViewKey = UnsafeRawPointer.init(bitPattern: "kEmptyViewKey".hashValue)
  13. }
  14. public var ly_emptyView: HDEmptyView? {
  15. set {
  16. objc_setAssociatedObject(self, RuntimeKey.kEmptyViewKey!, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
  17. for view in self.subviews {
  18. if view.isKind(of: HDEmptyView.classForCoder()) {
  19. view.removeFromSuperview()
  20. }
  21. }
  22. self.addSubview(ly_emptyView!)
  23. self.ly_emptyView?.isHidden = true
  24. }
  25. get {
  26. return objc_getAssociatedObject(self, RuntimeKey.kEmptyViewKey!) as? HDEmptyView
  27. }
  28. }
  29. //MAKR: --- 根据 DataSource 判断是否自动显示 emptyView
  30. public func ly_startLoading() {
  31. self.ly_emptyView?.isHidden = true
  32. }
  33. public func ly_endLoading() {
  34. getDataAndSet()
  35. }
  36. //手动控制显隐方法,不受DataSource的影响,需要把 autoShowEmptyView = false
  37. public func ly_showEmptyView() {
  38. self.ly_emptyView?.superview?.layoutSubviews()
  39. self.ly_emptyView?.isHidden = false
  40. //始终保持显示在最上层
  41. if self.ly_emptyView != nil {
  42. self.bringSubviewToFront(self.ly_emptyView!)
  43. }
  44. }
  45. public func ly_hideEmptyView() {
  46. self.ly_emptyView?.isHidden = true
  47. }
  48. //MARK: - Private Method
  49. fileprivate func totalDataCount() -> NSInteger {
  50. var totalCount: NSInteger = 0
  51. if self.isKind(of: UITableView.classForCoder()) {
  52. let tableView = self as? UITableView
  53. if (tableView?.numberOfSections)! >= 1 {
  54. for section in 0...(tableView?.numberOfSections)!-1 {
  55. totalCount += (tableView?.numberOfRows(inSection: section))!
  56. }
  57. }
  58. }
  59. else if self.isKind(of: UICollectionView.classForCoder()) {
  60. let collectionView = self as? UICollectionView
  61. if (collectionView?.numberOfSections)! >= 1 {
  62. for section in 0...(collectionView?.numberOfSections)!-1 {
  63. totalCount += (collectionView?.numberOfItems(inSection: section))!
  64. }
  65. }
  66. }
  67. return totalCount
  68. }
  69. fileprivate func getDataAndSet() {
  70. if self.totalDataCount() == 0 {
  71. show()
  72. } else {
  73. hide()
  74. }
  75. }
  76. fileprivate func show() {
  77. if self.ly_emptyView?.autoShowEmptyView == false {
  78. self.ly_emptyView?.isHidden = true
  79. return
  80. }
  81. ly_showEmptyView()
  82. }
  83. fileprivate func hide() {
  84. if self.ly_emptyView?.autoShowEmptyView == false {
  85. self.ly_emptyView?.isHidden = true
  86. return
  87. }
  88. ly_hideEmptyView()
  89. }
  90. }
  91. //MARK: ------ UITableView ------
  92. extension UITableView:SelfAware {
  93. static func awake() {
  94. UITableView.classInit()
  95. }
  96. static func classInit() {
  97. swizzleMethod
  98. }
  99. private static let swizzleMethod: Void = {
  100. //insertSections
  101. let originalSelector = #selector(insertSections(_:with:))
  102. let swizzledSelector = #selector(ly_insertSections(_:with:))
  103. HDRunTime.exchangeMethod(selector: originalSelector, replace: swizzledSelector, class: UITableView.self)
  104. //deleteSections
  105. let originalSelector1 = #selector(deleteSections(_:with:))
  106. let swizzledSelector1 = #selector(ly_deleteSections(_:with:))
  107. HDRunTime.exchangeMethod(selector: originalSelector1, replace: swizzledSelector1, class: UITableView.self)
  108. //insertRows
  109. let originalSelector2 = #selector(insertRows(at:with:))
  110. let swizzledSelector2 = #selector(ly_insertRowsAtIndexPaths(at:with:))
  111. HDRunTime.exchangeMethod(selector: originalSelector2, replace: swizzledSelector2, class: UITableView.self)
  112. //deleteRows
  113. let originalSelector3 = #selector(deleteRows(at:with:))
  114. let swizzledSelector3 = #selector(ly_deleteRowsAtIndexPaths(at:with:))
  115. HDRunTime.exchangeMethod(selector: originalSelector3, replace: swizzledSelector3, class: UITableView.self)
  116. //reload
  117. let originalSelector4 = #selector(UITableView.reloadData as (UITableView) -> () -> Void)
  118. let swizzledSelector4 = #selector(ly_reloadData)
  119. HDRunTime.exchangeMethod(selector: originalSelector4, replace: swizzledSelector4, class: UITableView.self)
  120. }()
  121. //section
  122. @objc func ly_insertSections(_ sections: NSIndexSet, with animation: UITableView.RowAnimation) {
  123. ly_insertSections(sections, with: animation)
  124. getDataAndSet()
  125. }
  126. @objc func ly_deleteSections(_ sections: NSIndexSet, with animation: UITableView.RowAnimation) {
  127. ly_deleteSections(sections, with: animation)
  128. getDataAndSet()
  129. }
  130. //row
  131. @objc func ly_insertRowsAtIndexPaths(at indexPaths: [IndexPath], with animation: UITableView.RowAnimation){
  132. ly_insertRowsAtIndexPaths(at: indexPaths, with: animation)
  133. getDataAndSet()
  134. }
  135. @objc func ly_deleteRowsAtIndexPaths(at indexPaths: [IndexPath], with animation: UITableView.RowAnimation){
  136. ly_deleteRowsAtIndexPaths(at: indexPaths, with: animation)
  137. getDataAndSet()
  138. }
  139. //reloadData
  140. @objc func ly_reloadData() {
  141. self.ly_reloadData()
  142. self.getDataAndSet()
  143. }
  144. }
  145. //MARK: ------ UICollectionView ------
  146. extension UICollectionView:SelfAware {
  147. static func awake() {
  148. UICollectionView.classInit()
  149. }
  150. static func classInit() {
  151. swizzleMethod
  152. }
  153. private static let swizzleMethod: Void = {
  154. //insertSections
  155. let originalSelector = #selector(insertSections(_:))
  156. let swizzledSelector = #selector(ly_insertSections(_:))
  157. HDRunTime.exchangeMethod(selector: originalSelector, replace: swizzledSelector, class: UICollectionView.self)
  158. //deleteSections
  159. let originalSelector1 = #selector(deleteSections(_:))
  160. let swizzledSelector1 = #selector(ly_deleteSections(_:))
  161. HDRunTime.exchangeMethod(selector: originalSelector1, replace: swizzledSelector1, class: UICollectionView.self)
  162. //insertRows
  163. let originalSelector2 = #selector(insertItems(at:))
  164. let swizzledSelector2 = #selector(ly_insertItemsAtIndexPaths(at:))
  165. HDRunTime.exchangeMethod(selector: originalSelector2, replace: swizzledSelector2, class: UICollectionView.self)
  166. //deleteRows
  167. let originalSelector3 = #selector(deleteItems(at:))
  168. let swizzledSelector3 = #selector(ly_deleteItemsAtIndexPaths(at:))
  169. HDRunTime.exchangeMethod(selector: originalSelector3, replace: swizzledSelector3, class: UICollectionView.self)
  170. //reload
  171. let originalSelector4 = #selector(UICollectionView.reloadData as (UICollectionView) -> () -> Void)
  172. let swizzledSelector4 = #selector(ly_reloadData)
  173. HDRunTime.exchangeMethod(selector: originalSelector4, replace: swizzledSelector4, class: UICollectionView.self)
  174. }()
  175. //section
  176. @objc func ly_insertSections(_ sections: NSIndexSet) {
  177. ly_insertSections(sections)
  178. getDataAndSet()
  179. }
  180. @objc func ly_deleteSections(_ sections: NSIndexSet) {
  181. ly_deleteSections(sections)
  182. getDataAndSet()
  183. }
  184. //item
  185. @objc func ly_insertItemsAtIndexPaths(at indexPaths: [IndexPath]){
  186. ly_insertItemsAtIndexPaths(at: indexPaths)
  187. getDataAndSet()
  188. }
  189. @objc func ly_deleteItemsAtIndexPaths(at indexPaths: [IndexPath]){
  190. ly_deleteItemsAtIndexPaths(at: indexPaths)
  191. getDataAndSet()
  192. }
  193. //reloadData
  194. @objc func ly_reloadData() {
  195. self.ly_reloadData()
  196. self.getDataAndSet()
  197. }
  198. }
  199. // MARK:- SelfAware 定义协议,使得程序在初始化的时候,将遵循该协议的类做了方法交换
  200. protocol SelfAware: class {
  201. static func awake()
  202. }
  203. class NothingToSeeHere {
  204. static func harmlessFunction() {
  205. let typeCount = Int(objc_getClassList(nil, 0))
  206. let types = UnsafeMutablePointer<AnyClass>.allocate(capacity: typeCount)
  207. let autoreleasingTypes = AutoreleasingUnsafeMutablePointer<AnyClass>(types)
  208. objc_getClassList(autoreleasingTypes, Int32(typeCount))
  209. for index in 0 ..< typeCount {
  210. (types[index] as? SelfAware.Type)?.awake()
  211. }
  212. //types.deallocate(capacity: typeCount)
  213. types.deallocate()
  214. }
  215. }
  216. extension UIApplication {
  217. private static let runOnce: Void = {
  218. NothingToSeeHere.harmlessFunction()
  219. }()
  220. override open var next: UIResponder? {
  221. // Called before applicationDidFinishLaunching
  222. UIApplication.runOnce
  223. return super.next
  224. }
  225. }