优惠券swift版马甲包

MFPageTitleView.swift 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. //
  2. // MFPageTitleView.swift
  3. // MFPagingViewExample
  4. // GitHub: https://github.com/wwx1991/MFPagingView
  5. // Created by iOS on 2018/6/12.
  6. // Copyright © 2018年 GM. All rights reserved.
  7. //
  8. protocol MFPageTitleViewDelegate: NSObjectProtocol {
  9. func selectedIndexInPageTitleView(pageTitleView: MFPageTitleView, selectedIndex: Int)
  10. }
  11. import UIKit
  12. class MFPageTitleView: UIView {
  13. var config: MFPageTitleViewConfig?
  14. //选中标题按钮下标,默认为 0
  15. var selectedIndex: Int = 0 {
  16. didSet {
  17. self.btnDidClick(sender: btnArr[selectedIndex])
  18. }
  19. }
  20. //scrollView
  21. private lazy var scrollView: UIScrollView = {
  22. let scrollV = UIScrollView(frame: self.bounds)
  23. scrollV.showsHorizontalScrollIndicator = false
  24. return scrollV
  25. }()
  26. //底部分隔线
  27. private lazy var line: UIView = {
  28. let lineV = UIView(frame: CGRect(x: 0, y: self.height-1, width: self.width, height: 1))
  29. lineV.backgroundColor = colorWithRGB(r: 244, g: 244, b: 244)
  30. return lineV
  31. }()
  32. //指示器
  33. private lazy var indicatorView: UIView = {
  34. let indicatorView = UIView(frame: CGRect(x: 0, y: scrollView.height-3, width: 0, height: 2))
  35. indicatorView.backgroundColor = self.config?.indicatorColor
  36. return indicatorView
  37. }()
  38. //标题数组
  39. private var titles = [String]()
  40. //存储标题按钮的数组
  41. private var btnArr = [UIButton]()
  42. //标记按钮下标
  43. private var signBtnIndex: Int = 0
  44. //按钮的总宽度
  45. private var allBtnWidth: CGFloat = 0
  46. private var lastBtn: UIButton?
  47. private var totalExtraWidth: CGFloat = 0
  48. weak var pageTitleViewDelegate: MFPageTitleViewDelegate?
  49. override init(frame: CGRect) {
  50. super.init(frame: frame)
  51. }
  52. convenience init(frame: CGRect, titles: [String], config: MFPageTitleViewConfig) {
  53. self.init()
  54. self.backgroundColor = UIColor.white
  55. self.frame = frame
  56. if titles.count < 1 {
  57. NSException(name: NSExceptionName(rawValue: "MFPagingView"), reason: "标题数组元素不能为0", userInfo: nil).raise()
  58. }
  59. self.titles = titles
  60. self.config = config
  61. setupUI()
  62. }
  63. deinit {
  64. print("deinit")
  65. }
  66. required init?(coder aDecoder: NSCoder) {
  67. fatalError("init(coder:) has not been implemented")
  68. }
  69. private func setupUI() {
  70. //处理偏移量
  71. let tempView = UIView(frame: CGRect.zero)
  72. self.addSubview(tempView)
  73. self.addSubview(scrollView)
  74. if let showBottomSeparator = self.config?.showBottomSeparator {
  75. if showBottomSeparator {
  76. self.addSubview(line)
  77. }
  78. }
  79. scrollView.insertSubview(indicatorView, at: 0)
  80. setupButtons()
  81. }
  82. private func setupButtons() {
  83. var totalTextWidth: CGFloat = 0
  84. for title in self.titles {
  85. // 计算所有按钮的文字宽度
  86. if let titleFont = self.config?.titleFont {
  87. let tempWidth = title.MF_widthWithString(font: titleFont, size: CGSize(width: 0, height: 0))
  88. totalTextWidth += tempWidth
  89. }
  90. }
  91. // 所有按钮文字宽度 + 按钮之间的间隔
  92. self.allBtnWidth = (self.config?.spacingBetweenButtons)! * (CGFloat)(self.titles.count + 1) + totalTextWidth
  93. let count: CGFloat = CGFloat(self.titles.count)
  94. if self.allBtnWidth <= self.bounds.width {
  95. var btnX: CGFloat = 0
  96. let btnY: CGFloat = 0
  97. let btnH: CGFloat = self.bounds.height
  98. for (index, title) in self.titles.enumerated() {
  99. var btnW: CGFloat = self.bounds.width / count
  100. let tempWidth = title.MF_widthWithString(font: (self.config?.titleFont)!, size: CGSize(width: 0, height: 0)) + (self.config?.spacingBetweenButtons)!
  101. if tempWidth > btnW {
  102. let extraWidth = tempWidth - btnW
  103. btnW = tempWidth
  104. totalExtraWidth += extraWidth
  105. }
  106. let btn = UIButton(type: .custom)
  107. btn.frame = CGRect(x: btnX, y: btnY, width: btnW, height: btnH)
  108. btnX += btnW
  109. btn.tag = index
  110. btn.setTitle(title, for: .normal)
  111. btn.setTitleColor(self.config?.titleColor, for: .normal)
  112. btn.setTitleColor(self.config?.titleSelectedColor, for: .selected)
  113. btn.titleLabel?.font = self.config?.titleFont
  114. btn.addTarget(self, action: #selector(btnDidClick(sender:)), for: .touchUpInside)
  115. scrollView.addSubview(btn)
  116. btnArr.append(btn)
  117. }
  118. scrollView.contentSize = CGSize(width: self.bounds.width + totalExtraWidth, height: 0)
  119. }else {
  120. var btnX: CGFloat = 0
  121. let btnY: CGFloat = 0
  122. let btnH: CGFloat = self.bounds.height
  123. for (index, title) in self.titles.enumerated() {
  124. let btnW = title.MF_widthWithString(font: (self.config?.titleFont)!, size: CGSize(width: 0, height: 0)) + (self.config?.spacingBetweenButtons)!
  125. let btn = UIButton(type: .custom)
  126. btn.frame = CGRect(x: btnX, y: btnY, width: btnW, height: btnH)
  127. btnX += btnW
  128. btn.tag = index
  129. btn.setTitle(title, for: .normal)
  130. btn.setTitleColor(self.config?.titleColor, for: .normal)
  131. btn.setTitleColor(self.config?.titleSelectedColor, for: .selected)
  132. btn.titleLabel?.font = self.config?.titleFont
  133. btn.addTarget(self, action: #selector(btnDidClick(sender:)), for: .touchUpInside)
  134. scrollView.addSubview(btn)
  135. btnArr.append(btn)
  136. }
  137. let scrollViewWidth = scrollView.subviews.last?.frame.maxX
  138. scrollView.contentSize = CGSize(width: scrollViewWidth!, height: 0)
  139. }
  140. }
  141. //滚动标题选中按钮居中
  142. private func scrollCenter(selectedBtn: UIButton) {
  143. var offsetX = selectedBtn.centerX - self.width * 0.5
  144. if offsetX < 0 {
  145. offsetX = 0
  146. }
  147. let maxOffsetX = scrollView.contentSize.width - self.width
  148. if offsetX > maxOffsetX {
  149. offsetX = maxOffsetX
  150. }
  151. scrollView.setContentOffset(CGPoint(x: offsetX, y: 0), animated: true)
  152. }
  153. //改变按钮的选择状态
  154. private func changeSelectedButton(button: UIButton) {
  155. if self.lastBtn == nil {
  156. button.isSelected = true
  157. self.lastBtn = button
  158. } else if self.lastBtn != nil && self.lastBtn == button {
  159. button.isSelected = true
  160. } else if self.lastBtn != button && self.lastBtn != nil {
  161. self.lastBtn?.isSelected = false
  162. button.isSelected = true
  163. self.lastBtn = button
  164. }
  165. }
  166. override func layoutSubviews() {
  167. super.layoutSubviews()
  168. //选中按钮下标初始值
  169. let lastBtn: UIButton = self.btnArr.last!
  170. if lastBtn.tag >= selectedIndex && selectedIndex >= 0 {
  171. btnDidClick(sender: self.btnArr[selectedIndex])
  172. }else {
  173. return
  174. }
  175. }
  176. }
  177. extension MFPageTitleView {
  178. @objc func btnDidClick(sender:UIButton) {
  179. self.changeSelectedButton(button: sender)
  180. scrollCenter(selectedBtn: sender)
  181. if self.allBtnWidth > self.width || totalExtraWidth > 0 {
  182. scrollCenter(selectedBtn: sender)
  183. }
  184. UIView.animate(withDuration: 0.1) {
  185. self.indicatorView.width = sender.currentTitle!.MF_widthWithString(font: (self.config?.titleFont)!, size: CGSize(width: 0, height: 0))
  186. self.indicatorView.center.x = sender.centerX
  187. }
  188. pageTitleViewDelegate?.selectedIndexInPageTitleView(pageTitleView: self, selectedIndex: sender.tag)
  189. self.signBtnIndex = sender.tag
  190. }
  191. }
  192. extension MFPageTitleView {
  193. //给外界提供的方法
  194. func setPageTitleView(progress: CGFloat, originalIndex: Int, targetIndex: Int) {
  195. let originalBtn: UIButton = self.btnArr[originalIndex]
  196. let targetBtn: UIButton = self.btnArr[targetIndex]
  197. self.signBtnIndex = targetBtn.tag
  198. scrollCenter(selectedBtn: targetBtn)
  199. //处理指示器的逻辑
  200. if self.allBtnWidth <= self.bounds.width {
  201. if totalExtraWidth > 0 {
  202. indicatorScrollAtScroll(progress: progress, originalBtn: originalBtn, targetBtn: targetBtn)
  203. }else {
  204. indicatorScrollAtStatic(progress: progress, originalBtn: originalBtn, targetBtn: targetBtn)
  205. }
  206. }else {
  207. indicatorScrollAtScroll(progress: progress, originalBtn: originalBtn, targetBtn: targetBtn)
  208. }
  209. }
  210. private func indicatorScrollAtStatic(progress: CGFloat, originalBtn: UIButton, targetBtn: UIButton) {
  211. if (progress >= 0.8) {
  212. changeSelectedButton(button: targetBtn)
  213. }
  214. /// 计算 indicatorView 偏移量
  215. let targetBtnTextWidth: CGFloat = (targetBtn.currentTitle?.MF_widthWithString(font: (self.config?.titleFont)!, size: CGSize.zero))!
  216. let targetBtnIndicatorX: CGFloat = targetBtn.frame.maxX - targetBtnTextWidth - 0.5 * (self.width / CGFloat(self.titles.count) - targetBtnTextWidth)
  217. let originalBtnTextWidth: CGFloat = (originalBtn.currentTitle?.MF_widthWithString(font: (self.config?.titleFont)!, size: CGSize.zero))!
  218. let originalBtnIndicatorX: CGFloat = originalBtn.frame.maxX - originalBtnTextWidth - 0.5 * (self.width / CGFloat(self.titles.count) - originalBtnTextWidth)
  219. let totalOffsetX: CGFloat = targetBtnIndicatorX - originalBtnIndicatorX
  220. let btnWidth: CGFloat = self.width / CGFloat(self.titles.count)
  221. let targetBtnRightTextX: CGFloat = targetBtn.frame.maxX - 0.5 * (btnWidth - targetBtnTextWidth)
  222. let originalBtnRightTextX: CGFloat = originalBtn.frame.maxX - 0.5 * (btnWidth - originalBtnTextWidth)
  223. let totalRightTextDistance: CGFloat = targetBtnRightTextX - originalBtnRightTextX
  224. let offsetX: CGFloat = totalOffsetX * progress
  225. let distance: CGFloat = progress * (totalRightTextDistance - totalOffsetX)
  226. self.indicatorView.x = originalBtnIndicatorX + offsetX
  227. let tempIndicatorWidth: CGFloat = originalBtnTextWidth + distance
  228. if tempIndicatorWidth >= targetBtn.width {
  229. let moveTotalX: CGFloat = targetBtn.x - originalBtn.x
  230. let moveX: CGFloat = moveTotalX * progress
  231. self.indicatorView.center.x = originalBtn.centerX + moveX
  232. } else {
  233. self.indicatorView.width = tempIndicatorWidth
  234. }
  235. }
  236. private func indicatorScrollAtScroll(progress: CGFloat, originalBtn: UIButton, targetBtn: UIButton) {
  237. if (progress >= 0.8) {
  238. changeSelectedButton(button: targetBtn)
  239. }
  240. let totalOffsetX: CGFloat = targetBtn.x - originalBtn.x
  241. let totalDistance: CGFloat = targetBtn.frame.maxX - originalBtn.frame.maxX
  242. var offsetX: CGFloat = 0
  243. var distance: CGFloat = 0
  244. let targetBtnTextWidth: CGFloat = (targetBtn.currentTitle?.MF_widthWithString(font: (self.config?.titleFont)!, size: CGSize.zero))!
  245. let tempIndicatorWidth: CGFloat = targetBtnTextWidth
  246. if tempIndicatorWidth >= targetBtn.width {
  247. offsetX = totalOffsetX * progress
  248. distance = progress * totalDistance - totalOffsetX
  249. self.indicatorView.x = originalBtn.x + offsetX
  250. self.indicatorView.width = originalBtn.width + distance
  251. } else {
  252. offsetX = totalOffsetX * progress + 0.5 * (self.config?.spacingBetweenButtons)!
  253. distance = progress * (totalDistance - totalOffsetX) - (self.config?.spacingBetweenButtons)!
  254. self.indicatorView.x = originalBtn.x + offsetX;
  255. self.indicatorView.width = originalBtn.width + distance
  256. }
  257. }
  258. }
  259. extension String {
  260. func MF_widthWithString(font: UIFont, size: CGSize) -> CGFloat {
  261. let rect = NSString(string: self).boundingRect(with: CGSize(width: size.width, height: size.height), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
  262. return ceil(rect.width)
  263. }
  264. }