JXSegmentedTitleDataSource.swift 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. //
  2. // JXSegmentedTitleView.swift
  3. // JXSegmentedView
  4. //
  5. // Created by jiaxin on 2018/12/26.
  6. // Copyright © 2018 jiaxin. All rights reserved.
  7. //
  8. import UIKit
  9. open class JXSegmentedTitleDataSource: JXSegmentedBaseDataSource{
  10. /// title数组
  11. open var titles = [String]()
  12. /// 如果将JXSegmentedView嵌套进UITableView的cell,每次重用的时候,JXSegmentedView进行reloadData时,会重新计算所有的title宽度。所以该应用场景,需要UITableView的cellModel缓存titles的文字宽度,再通过该闭包方法返回给JXSegmentedView。
  13. open var widthForTitleClosure: ((String)->(CGFloat))?
  14. /// label的numberOfLines
  15. open var titleNumberOfLines: Int = 1
  16. /// title普通状态的textColor
  17. open var titleNormalColor: UIColor = .black
  18. /// title选中状态的textColor
  19. open var titleSelectedColor: UIColor = .red
  20. /// title普通状态时的字体
  21. open var titleNormalFont: UIFont = UIFont.systemFont(ofSize: 15)
  22. /// title选中时的字体。如果不赋值,就默认与titleNormalFont一样
  23. open var titleSelectedFont: UIFont?
  24. /// title的颜色是否渐变过渡
  25. open var isTitleColorGradientEnabled: Bool = false
  26. /// title是否缩放。使用该效果时,务必保证titleNormalFont和titleSelectedFont值相同。
  27. open var isTitleZoomEnabled: Bool = false
  28. /// isTitleZoomEnabled为true才生效。是对字号的缩放,比如titleNormalFont的pointSize为10,放大之后字号就是10*1.2=12。
  29. open var titleSelectedZoomScale: CGFloat = 1.2
  30. /// title的线宽是否允许粗细。使用该效果时,务必保证titleNormalFont和titleSelectedFont值相同。
  31. open var isTitleStrokeWidthEnabled: Bool = false
  32. /// 用于控制字体的粗细(底层通过NSStrokeWidthAttributeName实现),负数越小字体越粗。
  33. open var titleSelectedStrokeWidth: CGFloat = -2
  34. /// title是否使用遮罩过渡
  35. open var isTitleMaskEnabled: Bool = false
  36. open override func preferredItemCount() -> Int {
  37. return titles.count
  38. }
  39. open override func preferredItemModelInstance() -> JXSegmentedBaseItemModel {
  40. return JXSegmentedTitleItemModel()
  41. }
  42. open override func preferredRefreshItemModel( _ itemModel: JXSegmentedBaseItemModel, at index: Int, selectedIndex: Int) {
  43. super.preferredRefreshItemModel(itemModel, at: index, selectedIndex: selectedIndex)
  44. guard let myItemModel = itemModel as? JXSegmentedTitleItemModel else {
  45. return
  46. }
  47. myItemModel.title = titles[index]
  48. myItemModel.textWidth = widthForTitle(myItemModel.title ?? "")
  49. myItemModel.titleNumberOfLines = titleNumberOfLines
  50. myItemModel.isSelectedAnimable = isSelectedAnimable
  51. myItemModel.titleNormalColor = titleNormalColor
  52. myItemModel.titleSelectedColor = titleSelectedColor
  53. myItemModel.titleNormalFont = titleNormalFont
  54. myItemModel.titleSelectedFont = titleSelectedFont != nil ? titleSelectedFont! : titleNormalFont
  55. myItemModel.isTitleZoomEnabled = isTitleZoomEnabled
  56. myItemModel.isTitleStrokeWidthEnabled = isTitleStrokeWidthEnabled
  57. myItemModel.isTitleMaskEnabled = isTitleMaskEnabled
  58. myItemModel.titleNormalZoomScale = 1
  59. myItemModel.titleSelectedZoomScale = titleSelectedZoomScale
  60. myItemModel.titleSelectedStrokeWidth = titleSelectedStrokeWidth
  61. myItemModel.titleNormalStrokeWidth = 0
  62. if index == selectedIndex {
  63. myItemModel.titleCurrentColor = titleSelectedColor
  64. myItemModel.titleCurrentZoomScale = titleSelectedZoomScale
  65. myItemModel.titleCurrentStrokeWidth = titleSelectedStrokeWidth
  66. }else {
  67. myItemModel.titleCurrentColor = titleNormalColor
  68. myItemModel.titleCurrentZoomScale = 1
  69. myItemModel.titleCurrentStrokeWidth = 0
  70. }
  71. }
  72. open func widthForTitle(_ title: String) -> CGFloat {
  73. if widthForTitleClosure != nil {
  74. return widthForTitleClosure!(title)
  75. }else {
  76. let textWidth = NSString(string: title).boundingRect(with: CGSize(width: CGFloat.infinity, height: CGFloat.infinity), options: [.usesFontLeading, .usesLineFragmentOrigin], attributes: [NSAttributedString.Key.font : titleNormalFont], context: nil).size.width
  77. return CGFloat(ceilf(Float(textWidth)))
  78. }
  79. }
  80. /// 因为该方法会被频繁调用,所以应该在`preferredRefreshItemModel( _ itemModel: JXSegmentedBaseItemModel, at index: Int, selectedIndex: Int)`方法里面,根据数据源计算好文字宽度,然后缓存起来。该方法直接使用已经计算好的文字宽度即可。
  81. open override func preferredSegmentedView(_ segmentedView: JXSegmentedView, widthForItemAt index: Int) -> CGFloat {
  82. var width = super.preferredSegmentedView(segmentedView, widthForItemAt: index)
  83. if itemWidth == JXSegmentedViewAutomaticDimension {
  84. width += (dataSource[index] as! JXSegmentedTitleItemModel).textWidth
  85. }else {
  86. width += itemWidth
  87. }
  88. return width
  89. }
  90. //MARK: - JXSegmentedViewDataSource
  91. open override func registerCellClass(in segmentedView: JXSegmentedView) {
  92. segmentedView.collectionView.register(JXSegmentedTitleCell.self, forCellWithReuseIdentifier: "cell")
  93. }
  94. open override func segmentedView(_ segmentedView: JXSegmentedView, cellForItemAt index: Int) -> JXSegmentedBaseCell {
  95. let cell = segmentedView.dequeueReusableCell(withReuseIdentifier: "cell", at: index)
  96. return cell
  97. }
  98. public override func segmentedView(_ segmentedView: JXSegmentedView, widthForItemContentAt index: Int) -> CGFloat {
  99. let model = dataSource[index] as! JXSegmentedTitleItemModel
  100. if isTitleZoomEnabled {
  101. return model.textWidth*model.titleCurrentZoomScale
  102. }else {
  103. return model.textWidth
  104. }
  105. }
  106. open override func refreshItemModel(_ segmentedView: JXSegmentedView, leftItemModel: JXSegmentedBaseItemModel, rightItemModel: JXSegmentedBaseItemModel, percent: CGFloat) {
  107. super.refreshItemModel(segmentedView, leftItemModel: leftItemModel, rightItemModel: rightItemModel, percent: percent)
  108. guard let leftModel = leftItemModel as? JXSegmentedTitleItemModel, let rightModel = rightItemModel as? JXSegmentedTitleItemModel else {
  109. return
  110. }
  111. if isTitleZoomEnabled && isItemTransitionEnabled {
  112. leftModel.titleCurrentZoomScale = JXSegmentedViewTool.interpolate(from: leftModel.titleSelectedZoomScale, to: leftModel.titleNormalZoomScale, percent: CGFloat(percent))
  113. rightModel.titleCurrentZoomScale = JXSegmentedViewTool.interpolate(from: rightModel.titleNormalZoomScale, to: rightModel.titleSelectedZoomScale, percent: CGFloat(percent))
  114. }
  115. if isTitleStrokeWidthEnabled && isItemTransitionEnabled {
  116. leftModel.titleCurrentStrokeWidth = JXSegmentedViewTool.interpolate(from: leftModel.titleSelectedStrokeWidth, to: leftModel.titleNormalStrokeWidth, percent: CGFloat(percent))
  117. rightModel.titleCurrentStrokeWidth = JXSegmentedViewTool.interpolate(from: rightModel.titleNormalStrokeWidth, to: rightModel.titleSelectedStrokeWidth, percent: CGFloat(percent))
  118. }
  119. if isTitleColorGradientEnabled && isItemTransitionEnabled {
  120. leftModel.titleCurrentColor = JXSegmentedViewTool.interpolateColor(from: leftModel.titleSelectedColor, to: leftModel.titleNormalColor, percent: percent)
  121. rightModel.titleCurrentColor = JXSegmentedViewTool.interpolateColor(from:rightModel.titleNormalColor , to:rightModel.titleSelectedColor, percent: percent)
  122. }
  123. }
  124. open override func refreshItemModel(_ segmentedView: JXSegmentedView, currentSelectedItemModel: JXSegmentedBaseItemModel, willSelectedItemModel: JXSegmentedBaseItemModel, selectedType: JXSegmentedViewItemSelectedType) {
  125. super.refreshItemModel(segmentedView, currentSelectedItemModel: currentSelectedItemModel, willSelectedItemModel: willSelectedItemModel, selectedType: selectedType)
  126. guard let myCurrentSelectedItemModel = currentSelectedItemModel as? JXSegmentedTitleItemModel, let myWillSelectedItemModel = willSelectedItemModel as? JXSegmentedTitleItemModel else {
  127. return
  128. }
  129. myCurrentSelectedItemModel.titleCurrentColor = myCurrentSelectedItemModel.titleNormalColor
  130. myCurrentSelectedItemModel.titleCurrentZoomScale = myCurrentSelectedItemModel.titleNormalZoomScale
  131. myCurrentSelectedItemModel.titleCurrentStrokeWidth = myCurrentSelectedItemModel.titleNormalStrokeWidth
  132. myCurrentSelectedItemModel.indicatorConvertToItemFrame = CGRect.zero
  133. myWillSelectedItemModel.titleCurrentColor = myWillSelectedItemModel.titleSelectedColor
  134. myWillSelectedItemModel.titleCurrentZoomScale = myWillSelectedItemModel.titleSelectedZoomScale
  135. myWillSelectedItemModel.titleCurrentStrokeWidth = myWillSelectedItemModel.titleSelectedStrokeWidth
  136. }
  137. }