Swift-根据滑动距离计算标题颜色和下划线距离

2018-12-24  本文已影响0人  向日葵的夏天_summer

在scrollView滑动的过程中,改变对应title的颜色以及下划线的颜色;

1.效果图

Dec-24-2018 17-27-53.gif

2.实现过程

首先第一部分代码如下:

class HeaderTitleView: UIView {
  
  private let tagNumber = 100
  private var titleW: CGFloat = 0
  private var titles: [String]?
  private var titleLabels: [UILabel] = []
  private var lineView: UIView = UIView()
  
  typealias HeaderTitleColor = (r: CGFloat, g: CGFloat, b: CGFloat)
  let normalColor = HeaderTitleColor(109, 109, 109)
  let selectedColor = HeaderTitleColor(238, 154, 72)
  
  var didClickTitle: SimpleCallBackWitInt?

  // 当前选中的索引
  private var selectedIndex: Int = 0
  
  init(frame: CGRect, titles: [String]) {
      self.titles = titles
      
      super.init(frame: frame)
      
      addTitleLabels()
  }
  
  func addTitleLabels() {
      backgroundColor = UIColor.white
      guard let titles = titles, titles.count > 0 else { return }
      
      titleW = SCREEN_WIDTH / CGFloat(titles.count)
      let titleH: CGFloat = self.frame.height
      var titleX: CGFloat = 0
      
      for i in 0..<titles.count {
          titleX = CGFloat(i) * titleW
          let label = UILabel(frame: CGRect(x: titleX, y: 0, width: titleW, height: titleH))
          label.tag = tagNumber + i
          label.text = titles[i]
          label.font = UIFont.systemFont(ofSize: 15)
          label.textAlignment = .center
          label.isUserInteractionEnabled = true
          label.textColor = UIColor(red: normalColor.r / 255.0, green: normalColor.g / 255.0, blue: normalColor.b / 255.0, alpha: 1.0)
          
          let tap = UITapGestureRecognizer(target: self, action: #selector(titleLabelDidClick(gesture:)))
          label.addGestureRecognizer(tap)
          
          addSubview(label)
          titleLabels.append(label)
          
          if i == 0 {
              label.textColor = UIColor(red: selectedColor.r / 255.0, green: selectedColor.g / 255.0, blue: selectedColor.b / 255.0, alpha: 1.0)
          }
      }
      
      lineView.frame = CGRect(x: 0, y: self.frame.height - 2, width: titleW, height: 2)
      lineView.backgroundColor = UIColor.orange
      addSubview(lineView)
  }
  
  @objc func titleLabelDidClick(gesture: UITapGestureRecognizer) {
      guard let label = gesture.view as? UILabel else { return }
      guard label.tag - tagNumber != selectedIndex else { return }
      
      let lastLabel = self.titleLabels[selectedIndex]
      lastLabel.textColor = UIColor(red: normalColor.r / 255.0, green: normalColor.g / 255.0, blue: normalColor.b / 255.0, alpha: 1.0)
      label.textColor = UIColor(red: selectedColor.r / 255.0, green: selectedColor.g / 255.0, blue: selectedColor.b / 255.0, alpha: 1.0)

      lineView.frame.origin.x = label.frame.origin.x
      
      selectedIndex = label.tag - tagNumber

      didClickTitle?(selectedIndex)
  }
  
  func changeTitleLineView(lastIndex: Int, toIndex: Int, percent: CGFloat) {
      let lastLabel = self.titleLabels[lastIndex]
      let toLabel = self.titleLabels[toIndex]
      
      let offsetX = toLabel.frame.origin.x - lastLabel.frame.origin.x
      
      let deltaX = offsetX * percent

      lineView.frame = CGRect(x: lastLabel.frame.origin.x + deltaX, y: lineView.frame.origin.y, width: lineView.frame.size.width, height: lineView.frame.size.height)
      
      let colorDelta: HeaderTitleColor = (selectedColor.r - normalColor.r, selectedColor.g - normalColor.g, selectedColor.b - normalColor.b)
      lastLabel.textColor = UIColor(red: (selectedColor.r - colorDelta.r * percent) / 255.0, green: (selectedColor.g - colorDelta.g * percent) / 255.0, blue: (selectedColor.b - colorDelta.b * percent) / 255.0, alpha: 1.0)
      toLabel.textColor = UIColor(red: (normalColor.r + colorDelta.r * percent) / 255.0, green: (normalColor.g + colorDelta.g * percent) / 255.0, blue: (normalColor.b + colorDelta.b * percent) / 255.0, alpha: 1.0)
      
      selectedIndex = toIndex
  }
  
  required init?(coder aDecoder: NSCoder) {
      fatalError("init(coder:) has not been implemented")
  }
  
}

第二部分代码:

class MainContentView: UIView {

    var isHeaderClick: Bool = false
    private var startOffsetX: CGFloat = 0
    private var childVCs: [UIViewController] = []
    var didScrollToIndex: SimpleCallBackWithPercent?
    
    private lazy var collectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        layout.minimumLineSpacing = 0
        layout.minimumInteritemSpacing = 0
        layout.itemSize = CGSize(width: SCREEN_WIDTH, height: KContentHeight)
        let collection = UICollectionView(frame: self.bounds, collectionViewLayout: layout)
        collection.isPagingEnabled = true
        return collection
    }()
    
    init(frame: CGRect, childVCs: [UIViewController]) {
        super.init(frame: frame)
        
        self.childVCs = childVCs
        addSubviews()
    }
    
    func addSubviews() {
        collectionView.backgroundColor = UIColor.white
        collectionView.delegate = self
        collectionView.dataSource = self
        collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "UICollectionViewCellID")
        addSubview(collectionView)
        
    }
    
    func scrollToPage(index: Int) {
        
        collectionView.setContentOffset(CGPoint(x: CGFloat(index) * SCREEN_WIDTH, y: 0), animated: false)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}

extension MainContentView: UICollectionViewDataSource {
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return childVCs.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "UICollectionViewCellID", for: indexPath)
        let view = childVCs[indexPath.row].view!
        view.backgroundColor = indexPath.row % 2 == 0 ? .lightGray : .cyan
        cell.addSubview(view)
        return cell
    }
}

extension MainContentView: UICollectionViewDelegate {
    
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        
        isHeaderClick = false
        startOffsetX = scrollView.contentOffset.x
    }
    
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        // 如果点击titleView,就不用计算percent
        guard isHeaderClick == false else { return }
        
        var lastIndex = 0
        var toIndex = 0
        var percent: CGFloat = 0
        
        let offsetX = scrollView.contentOffset.x
        if offsetX <= 0 || offsetX >= CGFloat(childVCs.count - 1) * SCREEN_WIDTH {
            return
        }

        if offsetX > startOffsetX { // 向左滑动
            percent = (offsetX - startOffsetX) / SCREEN_WIDTH
            lastIndex = Int(offsetX / SCREEN_WIDTH)
            toIndex = lastIndex + 1
            
            if toIndex >= childVCs.count {
                toIndex = childVCs.count - 1
            }
            
            if offsetX - startOffsetX == SCREEN_WIDTH {
                percent = 1.0
                toIndex = lastIndex
            }

            didScrollToIndex?(lastIndex, toIndex, percent)

        } else {
            percent = 1.0 - (offsetX / SCREEN_WIDTH - floor(offsetX / SCREEN_WIDTH))
            toIndex = Int(offsetX / SCREEN_WIDTH)
            lastIndex = toIndex + 1
            
            if toIndex >= childVCs.count {
                toIndex = childVCs.count - 1
            }
            
            if startOffsetX - offsetX == SCREEN_WIDTH {
                lastIndex = toIndex
            }
  
            didScrollToIndex?(lastIndex, toIndex, percent)
        }
    }

}

第三部分代码:

import UIKit

private let KHeaderHeight: CGFloat = 50
private let KContentHeight: CGFloat = SCREEN_HEIGHT - NavBarHeight - KHeaderHeight

typealias SimpleCallBackWitInt = (_ selIndex: Int) -> ()
typealias SimpleCallBackWithPercent = (_ lastIndex: Int, _ toIndex: Int, _ percent: CGFloat) -> ()

class Test08ViewController: BaseViewController {
  
    private lazy var titleView: HeaderTitleView = {
        let view = HeaderTitleView(frame: CGRect(x: 0, y: NavBarHeight, width: SCREEN_WIDTH, height: KHeaderHeight), titles: ["标题一", "标题二", "标题三", "标题四"])
        return view
    }()
    
    private lazy var contentView: MainContentView = {
        let vcs = [UIViewController(), UIViewController(), UIViewController(), UIViewController()]
        let view = MainContentView(frame: CGRect(x: 0, y: NavBarHeight + KHeaderHeight, width: SCREEN_WIDTH, height: KContentHeight), childVCs: vcs)
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        addSubviews()
    }
    
    func addSubviews() {
        view.addSubview(titleView)
        view.addSubview(contentView)
        
        titleView.didClickTitle = { [weak self] selIndex in
            self?.contentView.isHeaderClick = true
            self?.contentView.scrollToPage(index: selIndex)
        }
     
        contentView.didScrollToIndex = { [weak self] (lastIndex, toIndex, percent) in
            self?.titleView.changeTitleLineView(lastIndex: lastIndex, toIndex: toIndex, percent: percent)
        }
    }
 
}

上一篇下一篇

猜你喜欢

热点阅读