JXSegmentedBaseDataSource.swift 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. //
  2. // JXSegmentedBaseDataSource.swift
  3. // JXSegmentedView
  4. //
  5. // Created by jiaxin on 2018/12/28.
  6. // Copyright © 2018 jiaxin. All rights reserved.
  7. //
  8. import Foundation
  9. import UIKit
  10. open class JXSegmentedBaseDataSource: JXSegmentedViewDataSource {
  11. /// 最终传递给JXSegmentedView的数据源数组
  12. open var dataSource = [JXSegmentedBaseItemModel]()
  13. /// cell的内容宽度,为JXSegmentedViewAutomaticDimension时就以内容计算的宽度为准,否则以itemContentWidth的具体值为准。
  14. open var itemContentWidth: CGFloat = JXSegmentedViewAutomaticDimension
  15. /// 真实的item宽度 = itemContentWidth + itemWidthIncrement。
  16. open var itemWidthIncrement: CGFloat = 0
  17. /// item之前的间距
  18. open var itemSpacing: CGFloat = 20
  19. /// 当collectionView.contentSize.width小于JXSegmentedView的宽度时,是否将itemSpacing均分。
  20. open var isItemSpacingAverageEnabled: Bool = true
  21. /// item左右滚动过渡时,是否允许渐变。比如JXSegmentedTitleDataSource的titleZoom、titleNormalColor、titleStrokeWidth等渐变。
  22. open var isItemTransitionEnabled: Bool = true
  23. /// 选中的时候,是否需要动画过渡。自定义的cell需要自己处理动画过渡逻辑,动画处理逻辑参考`JXSegmentedTitleCell`
  24. open var isSelectedAnimable: Bool = false
  25. /// 选中动画的时长
  26. open var selectedAnimationDuration: TimeInterval = 0.25
  27. /// 是否允许item宽度缩放
  28. open var isItemWidthZoomEnabled: Bool = false
  29. /// item宽度选中时的scale
  30. open var itemWidthSelectedZoomScale: CGFloat = 1.5
  31. private var animator: JXSegmentedAnimator?
  32. deinit {
  33. animator?.stop()
  34. }
  35. public init() {
  36. }
  37. /// 配置完各种属性之后,需要手动调用该方法,更新数据源
  38. ///
  39. /// - Parameter selectedIndex: 当前选中的index
  40. open func reloadData(selectedIndex: Int) {
  41. dataSource.removeAll()
  42. }
  43. /// 子类需要重载该方法,用于返回自己定义的JXSegmentedBaseItemModel子类实例
  44. ///
  45. /// - Returns: JXSegmentedBaseItemModel子类实例
  46. open func preferredItemModelInstance() -> JXSegmentedBaseItemModel {
  47. return JXSegmentedBaseItemModel()
  48. }
  49. open func preferredSegmentedView(_ segmentedView: JXSegmentedView, widthForItemAt index: Int) -> CGFloat {
  50. return itemWidthIncrement
  51. }
  52. open func preferredRefreshItemModel(_ itemModel: JXSegmentedBaseItemModel, at index: Int, selectedIndex: Int) {
  53. itemModel.index = index
  54. itemModel.isItemTransitionEnabled = isItemTransitionEnabled
  55. itemModel.isSelectedAnimable = isSelectedAnimable
  56. itemModel.selectedAnimationDuration = selectedAnimationDuration
  57. itemModel.isItemWidthZoomEnabled = isItemWidthZoomEnabled
  58. itemModel.itemWidthNormalZoomScale = 1
  59. itemModel.itemWidthSelectedZoomScale = itemWidthSelectedZoomScale
  60. if index == selectedIndex {
  61. itemModel.isSelected = true
  62. itemModel.itemWidthCurrentZoomScale = itemModel.itemWidthSelectedZoomScale
  63. }else {
  64. itemModel.isSelected = false
  65. itemModel.itemWidthCurrentZoomScale = itemModel.itemWidthNormalZoomScale
  66. }
  67. }
  68. //MARK: - JXSegmentedViewDataSource
  69. open func itemDataSource(in segmentedView: JXSegmentedView) -> [JXSegmentedBaseItemModel] {
  70. return dataSource
  71. }
  72. /// 自定义子类请继承方法`func preferredWidthForItem(at index: Int) -> CGFloat`
  73. public final func segmentedView(_ segmentedView: JXSegmentedView, widthForItemAt index: Int, isItemWidthZoomValid: Bool) -> CGFloat {
  74. let itemWidth = preferredSegmentedView(segmentedView, widthForItemAt: index)
  75. if isItemWidthZoomEnabled && isItemWidthZoomValid {
  76. return itemWidth * dataSource[index].itemWidthCurrentZoomScale
  77. }else {
  78. return itemWidth
  79. }
  80. }
  81. open func registerCellClass(in segmentedView: JXSegmentedView) {
  82. }
  83. open func segmentedView(_ segmentedView: JXSegmentedView, cellForItemAt index: Int) -> JXSegmentedBaseCell {
  84. return JXSegmentedBaseCell()
  85. }
  86. open func refreshItemModel(_ segmentedView: JXSegmentedView, currentSelectedItemModel: JXSegmentedBaseItemModel, willSelectedItemModel: JXSegmentedBaseItemModel, selectedType: JXSegmentedViewItemSelectedType) {
  87. currentSelectedItemModel.isSelected = false
  88. willSelectedItemModel.isSelected = true
  89. if isItemWidthZoomEnabled {
  90. if (selectedType == .scroll && !isItemTransitionEnabled) ||
  91. selectedType == .click ||
  92. selectedType == .code {
  93. animator = JXSegmentedAnimator()
  94. animator?.duration = selectedAnimationDuration
  95. animator?.progressClosure = {[weak self] (percent) in
  96. currentSelectedItemModel.itemWidthCurrentZoomScale = JXSegmentedViewTool.interpolate(from: currentSelectedItemModel.itemWidthSelectedZoomScale, to: currentSelectedItemModel.itemWidthNormalZoomScale, percent: percent)
  97. currentSelectedItemModel.itemWidth = self?.segmentedView(segmentedView, widthForItemAt: currentSelectedItemModel.index, isItemWidthZoomValid: true) ?? 0
  98. willSelectedItemModel.itemWidthCurrentZoomScale = JXSegmentedViewTool.interpolate(from: willSelectedItemModel.itemWidthNormalZoomScale, to: willSelectedItemModel.itemWidthSelectedZoomScale, percent: percent)
  99. willSelectedItemModel.itemWidth = self?.segmentedView(segmentedView, widthForItemAt: willSelectedItemModel.index, isItemWidthZoomValid: true) ?? 0
  100. segmentedView.collectionView.collectionViewLayout.invalidateLayout()
  101. }
  102. animator?.start()
  103. }
  104. }else {
  105. currentSelectedItemModel.itemWidthCurrentZoomScale = currentSelectedItemModel.itemWidthNormalZoomScale
  106. willSelectedItemModel.itemWidthCurrentZoomScale = willSelectedItemModel.itemWidthSelectedZoomScale
  107. }
  108. }
  109. open func refreshItemModel(_ segmentedView: JXSegmentedView, leftItemModel: JXSegmentedBaseItemModel, rightItemModel: JXSegmentedBaseItemModel, percent: CGFloat) {
  110. //如果正在进行itemWidth缩放动画,用户又立马滚动了contentScrollView,需要停止动画。
  111. animator?.stop()
  112. if isItemWidthZoomEnabled && isItemTransitionEnabled {
  113. //允许itemWidth缩放动画且允许item渐变过渡
  114. leftItemModel.itemWidthCurrentZoomScale = JXSegmentedViewTool.interpolate(from: leftItemModel.itemWidthSelectedZoomScale, to: leftItemModel.itemWidthNormalZoomScale, percent: percent)
  115. leftItemModel.itemWidth = self.segmentedView(segmentedView, widthForItemAt: leftItemModel.index, isItemWidthZoomValid: true)
  116. rightItemModel.itemWidthCurrentZoomScale = JXSegmentedViewTool.interpolate(from: rightItemModel.itemWidthNormalZoomScale, to: rightItemModel.itemWidthSelectedZoomScale, percent: percent)
  117. rightItemModel.itemWidth = self.segmentedView(segmentedView, widthForItemAt: rightItemModel.index, isItemWidthZoomValid: true)
  118. segmentedView.collectionView.collectionViewLayout.invalidateLayout()
  119. }
  120. }
  121. /// 自定义子类请继承方法`func preferredRefreshItemModel(_ itemModel: JXSegmentedBaseItemModel, at index: Int, selectedIndex: Int)`
  122. public final func refreshItemModel(_ segmentedView: JXSegmentedView, _ itemModel: JXSegmentedBaseItemModel, at index: Int, selectedIndex: Int) {
  123. preferredRefreshItemModel(itemModel, at: index, selectedIndex: selectedIndex)
  124. }
  125. }