美文网首页
Swift-根据滑动距离计算标题颜色和下划线距离

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

作者: 向日葵的夏天_summer | 来源:发表于2018-12-24 17:34 被阅读0次

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

    1.效果图

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

    2.实现过程

    • 第一步,自定义titleView;
    • 第二步,自定义contentView;
    • 第三步,交互部分;

    首先第一部分代码如下:

    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)
            }
        }
     
    }
    
    

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/ckgzkqtx.html