HeaderFooterView.swift 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. // HeaderFooterView.swift
  2. // Eureka ( https://github.com/xmartlabs/Eureka )
  3. //
  4. // Copyright (c) 2016 Xmartlabs ( http://xmartlabs.com )
  5. //
  6. //
  7. // Permission is hereby granted, free of charge, to any person obtaining a copy
  8. // of this software and associated documentation files (the "Software"), to deal
  9. // in the Software without restriction, including without limitation the rights
  10. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. // copies of the Software, and to permit persons to whom the Software is
  12. // furnished to do so, subject to the following conditions:
  13. //
  14. // The above copyright notice and this permission notice shall be included in
  15. // all copies or substantial portions of the Software.
  16. //
  17. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. // THE SOFTWARE.
  24. import Foundation
  25. import UIKit
  26. /**
  27. Enumeration used to generate views for the header and footer of a section.
  28. - Class: Will generate a view of the specified class.
  29. - Callback->ViewType: Will generate the view as a result of the given closure.
  30. - NibFile: Will load the view from a nib file.
  31. */
  32. public enum HeaderFooterProvider<ViewType: UIView> {
  33. /**
  34. * Will generate a view of the specified class.
  35. */
  36. case `class`
  37. /**
  38. * Will generate the view as a result of the given closure.
  39. */
  40. case callback(()->ViewType)
  41. /**
  42. * Will load the view from a nib file.
  43. */
  44. case nibFile(name: String, bundle: Bundle?)
  45. internal func createView() -> ViewType {
  46. switch self {
  47. case .class:
  48. return ViewType()
  49. case .callback(let builder):
  50. return builder()
  51. case .nibFile(let nibName, let bundle):
  52. return (bundle ?? Bundle(for: ViewType.self)).loadNibNamed(nibName, owner: nil, options: nil)![0] as! ViewType
  53. }
  54. }
  55. }
  56. /**
  57. * Represents headers and footers of sections
  58. */
  59. public enum HeaderFooterType {
  60. case header, footer
  61. }
  62. /**
  63. * Struct used to generate headers and footers either from a view or a String.
  64. */
  65. public struct HeaderFooterView<ViewType: UIView> : ExpressibleByStringLiteral, HeaderFooterViewRepresentable {
  66. /// Holds the title of the view if it was set up with a String.
  67. public var title: String?
  68. /// Generates the view.
  69. public var viewProvider: HeaderFooterProvider<ViewType>?
  70. /// Closure called when the view is created. Useful to customize its appearance.
  71. public var onSetupView: ((_ view: ViewType, _ section: Section) -> Void)?
  72. /// A closure that returns the height for the header or footer view.
  73. public var height: (() -> CGFloat)?
  74. /**
  75. This method can be called to get the view corresponding to the header or footer of a section in a specific controller.
  76. - parameter section: The section from which to get the view.
  77. - parameter type: Either header or footer.
  78. - parameter controller: The controller from which to get that view.
  79. - returns: The header or footer of the specified section.
  80. */
  81. public func viewForSection(_ section: Section, type: HeaderFooterType) -> UIView? {
  82. var view: ViewType?
  83. if type == .header {
  84. view = section.headerView as? ViewType ?? {
  85. let result = viewProvider?.createView()
  86. section.headerView = result
  87. return result
  88. }()
  89. } else {
  90. view = section.footerView as? ViewType ?? {
  91. let result = viewProvider?.createView()
  92. section.footerView = result
  93. return result
  94. }()
  95. }
  96. guard let v = view else { return nil }
  97. onSetupView?(v, section)
  98. return v
  99. }
  100. /**
  101. Initiates the view with a String as title
  102. */
  103. public init?(title: String?) {
  104. guard let t = title else { return nil }
  105. self.init(stringLiteral: t)
  106. }
  107. /**
  108. Initiates the view with a view provider, ideal for customized headers or footers
  109. */
  110. public init(_ provider: HeaderFooterProvider<ViewType>) {
  111. viewProvider = provider
  112. }
  113. /**
  114. Initiates the view with a String as title
  115. */
  116. public init(unicodeScalarLiteral value: String) {
  117. self.title = value
  118. }
  119. /**
  120. Initiates the view with a String as title
  121. */
  122. public init(extendedGraphemeClusterLiteral value: String) {
  123. self.title = value
  124. }
  125. /**
  126. Initiates the view with a String as title
  127. */
  128. public init(stringLiteral value: String) {
  129. self.title = value
  130. }
  131. }
  132. extension UIView {
  133. func eurekaInvalidate() {
  134. setNeedsUpdateConstraints()
  135. updateConstraintsIfNeeded()
  136. setNeedsLayout()
  137. }
  138. }