SAIInputItemView.swift 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. //
  2. // SAIInputItemView.swift
  3. // SAIInputBar
  4. //
  5. // Created by SAGESSE on 8/3/16.
  6. // Copyright © 2016-2017 SAGESSE. All rights reserved.
  7. //
  8. import UIKit
  9. internal class SAIInputItemView: UICollectionViewCell {
  10. var item: SAIInputItem? {
  11. willSet {
  12. UIView.performWithoutAnimation {
  13. self._updateItem(newValue)
  14. }
  15. }
  16. }
  17. weak var delegate: SAIInputItemViewDelegate? {
  18. set { return _button.delegate = newValue }
  19. get { return _button.delegate }
  20. }
  21. func setSelected(_ selected: Bool, animated: Bool) {
  22. _button.setSelected(selected: selected, animated: animated)
  23. }
  24. func _init() {
  25. clipsToBounds = true
  26. backgroundColor = .clear
  27. //backgroundColor = UIColor.greenColor().colorWithAlphaComponent(0.2)
  28. }
  29. func _updateItem(_ newValue: SAIInputItem?) {
  30. guard let newValue = newValue else {
  31. // clear on nil
  32. _contentView?.removeFromSuperview()
  33. _contentView = nil
  34. return
  35. }
  36. if let customView = newValue.customView {
  37. // 需要显示自定义视图
  38. _contentView?.removeFromSuperview()
  39. _contentView = customView
  40. } else {
  41. // 显示普通按钮
  42. if _contentView !== _button {
  43. _contentView?.removeFromSuperview()
  44. _contentView = _button
  45. }
  46. // 更新按钮属性
  47. _button.barItem = newValue
  48. }
  49. // 更新视图
  50. if let view = _contentView, view.superview != contentView {
  51. view.frame = contentView.bounds
  52. view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
  53. contentView.addSubview(view)
  54. }
  55. }
  56. private var _contentView: UIView?
  57. private lazy var _button: SAIInputItemButton = {
  58. let view = SAIInputItemButton(type: .custom)
  59. //let view = SAIInputItemButton(type: .System)
  60. view.isMultipleTouchEnabled = false
  61. view.isExclusiveTouch = true
  62. return view
  63. }()
  64. override init(frame: CGRect) {
  65. super.init(frame: frame)
  66. _init()
  67. }
  68. required init?(coder aDecoder: NSCoder) {
  69. super.init(coder: aDecoder)
  70. _init()
  71. }
  72. }
  73. internal class SAIInputItemButton: UIButton {
  74. override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
  75. guard let barItem = self.barItem else {
  76. return super.beginTracking(touch, with: event)
  77. }
  78. if delegate?.barItem(shouldHighlightFor: barItem) ?? true {
  79. allowsHighlight = true
  80. delegate?.barItem(didHighlightFor: barItem)
  81. } else {
  82. allowsHighlight = false
  83. }
  84. return super.beginTracking(touch, with: event)
  85. }
  86. var barItem: SAIInputItem? {
  87. willSet {
  88. guard barItem !== newValue else {
  89. return
  90. }
  91. UIView.performWithoutAnimation {
  92. guard let item = newValue else {
  93. return
  94. }
  95. self._updateBarItem(item)
  96. }
  97. }
  98. }
  99. weak var delegate: SAIInputItemViewDelegate?
  100. var allowsHighlight = true
  101. var _selected: Bool = false
  102. override var isHighlighted: Bool {
  103. set {
  104. guard allowsHighlight else {
  105. return
  106. }
  107. super.isHighlighted = newValue
  108. _setHighlighted(newValue, animated: true)
  109. }
  110. get { return super.isHighlighted }
  111. }
  112. override var state: UIControl.State {
  113. // 永远禁止系统的选中
  114. return super.state.subtracting(.selected)
  115. }
  116. func setSelected(selected: Bool, animated: Bool) {
  117. //logger.trace(selected)
  118. let op1: UIControl.State = [(selected ? .selected : .normal), .normal]
  119. let op2: UIControl.State = [(selected ? .selected : .normal), .highlighted]
  120. let n = barItem?.image(for: op1) ?? barItem?.image(for: .normal)
  121. let h = barItem?.image(for: op2)
  122. setImage(n, for: .normal)
  123. setImage(h, for: .highlighted)
  124. if animated {
  125. _addAnimation("selected")
  126. }
  127. _selected = selected
  128. }
  129. private func _init() {
  130. addTarget(self, action: #selector(_touchHandler), for: .touchUpInside)
  131. }
  132. private func _addAnimation(_ key: String) {
  133. let ani = CATransition()
  134. ani.duration = 0.35
  135. ani.fillMode = CAMediaTimingFillMode.backwards
  136. ani.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
  137. ani.type = CATransitionType.fade
  138. ani.subtype = CATransitionSubtype.fromTop
  139. layer.add(ani, forKey: key)
  140. }
  141. private func _setHighlighted(_ highlighted: Bool, animated: Bool) {
  142. //logger.trace(highlighted)
  143. // 检查高亮的时候有没有设置图片, 如果有关闭系统的变透明效果
  144. if barItem?.image(for: [(isSelected ? .selected : .normal), .highlighted]) != nil {
  145. imageView?.alpha = 1
  146. }
  147. if animated {
  148. _addAnimation("highlighted")
  149. }
  150. }
  151. func _updateBarItem(_ item: SAIInputItem) {
  152. let states: [UIControl.State] = [
  153. [.normal],
  154. [.highlighted],
  155. [.disabled],
  156. [.selected, .normal],
  157. [.selected, .highlighted],
  158. [.selected, .disabled]
  159. ]
  160. tag = item.tag
  161. isEnabled = item.enabled
  162. imageEdgeInsets = item.imageInsets
  163. tintColor = item.tintColor
  164. backgroundColor = item.backgroundColor
  165. if let font = item.font {
  166. titleLabel?.font = font
  167. }
  168. states.forEach {
  169. setTitle(item.title(for: $0), for: $0)
  170. setTitleColor(item.titleColor(for: $0), for: $0)
  171. setTitleShadowColor(item.titleShadowColor(for: $0), for: $0)
  172. setAttributedTitle(item.attributedTitle(for: $0), for: $0)
  173. setImage(item.image(for: $0), for: $0)
  174. setBackgroundImage(item.backgroundImage(for: $0), for: $0)
  175. }
  176. setTitle(item.title, for: .normal)
  177. setImage(item.image, for: .normal)
  178. }
  179. @objc private func _touchHandler() {
  180. guard let barItem = barItem else {
  181. return
  182. }
  183. // delegate before the callback
  184. barItem.handler?(barItem)
  185. if !_selected {
  186. // select
  187. guard delegate?.barItem(shouldSelectFor: barItem) ?? true else {
  188. return
  189. }
  190. setSelected(selected: true, animated: true)
  191. delegate?.barItem(didSelectFor: barItem)
  192. } else {
  193. // Deselect
  194. guard delegate?.barItem(shouldDeselectFor: barItem) ?? true else {
  195. return
  196. }
  197. setSelected(selected: false, animated: true)
  198. delegate?.barItem(didDeselectFor: barItem)
  199. }
  200. }
  201. override init(frame: CGRect) {
  202. super.init(frame: frame)
  203. _init()
  204. }
  205. required init?(coder aDecoder: NSCoder) {
  206. super.init(coder: aDecoder)
  207. _init()
  208. }
  209. }
  210. internal protocol SAIInputItemViewDelegate: class {
  211. func barItem(shouldHighlightFor barItem: SAIInputItem) -> Bool
  212. func barItem(shouldDeselectFor barItem: SAIInputItem) -> Bool
  213. func barItem(shouldSelectFor barItem: SAIInputItem) -> Bool
  214. func barItem(didHighlightFor barItem: SAIInputItem)
  215. func barItem(didDeselectFor barItem: SAIInputItem)
  216. func barItem(didSelectFor barItem: SAIInputItem)
  217. }