美文网首页
swift 标题视图联动 颜色渐变 滚动条渐变

swift 标题视图联动 颜色渐变 滚动条渐变

作者: 江水东流 | 来源:发表于2017-07-03 15:43 被阅读176次

现在好多app(喜马拉雅,新浪微博等)都有类似UIPageViewController的效果,实际开发中我们要进行特殊效果,需要自定义,我写了一个swift版本的.效果如下
点击链接下载 github下载地址

  • 多标题,可以滑动
swift多控制器滚动.gif
  • 标题较少,上面不滚动,距离等分
swift多控制器滚动1.gif

这种效果有很多坑点,比如,快速连续滑动时候流畅性问题,字体颜色渐变色效果,标题尽量滑到居中位置,我要起始在非第一个控制器上等等.下面我把关键代码贴出来.

UI架构

我用的是父子控制器, parentVc.addChildViewController(vc),子控制器的视图放在父控制器的collectionView上显示.默认样式我用了一个JDPageStyle类专门进行处理.
标题较多时用 style.isScrollEnable = true 来让上面的标题可以滚动,标题较少时style.isScrollEnable = false上面距离等分.
上面用scrollView 下面用collectionView,互为对方的代理,对方代理传过来后自己滑动,自己滑动发送代理对方滚动,对方传来滑动消息自己滑动时,不发送代理.

fileprivate func setupUI() {
    // 1.将childVc添加到父控制器中
    for vc in childVcs {
        parentVc.addChildViewController(vc)
    }
    // 2.初始化用于显示子控制器View的View(UIScrollView/UICollectionView)
    addSubview(collectionView)
}

//设置contentView&titleView关系
titleView?.delegate = contentView
contentView?.delegate = titleView

  • 设置起始index时要用多线程,主线程异步,这样初始化完毕后才执行这个滚动方法.
    DispatchQueue.main.async {
            let indexPa = IndexPath(item: self.startIndex, section: 0)
            self.contentView?.collectionView.scrollToItem(at: indexPa, at: .centeredHorizontally, animated: false)
            self.contentView?.delegate?.contentView((self.contentView)!, targetIndex: self.startIndex, progress: 1)
            self.contentView?.delegate?.contentView( (self.contentView)!, endScroll: self.startIndex)
        }
  • 按钮滚动到尽量居中位置
    标签滑动中心位置大于屏幕一半时候,如果scrollView足够长,scrollview滑动,使标签居中
  var offsetX = newLabel.center.x - scrollView.bounds.width * 0.5
    if offsetX < 0 {
        offsetX = 0
    }

//滑动到后面,scrollview不能再滑动时候,不滑动
let maxOffset = scrollView.contentSize.width - bounds.width
if offsetX > maxOffset {
offsetX = maxOffset
}
scrollView.setContentOffset(CGPoint(x: offsetX, y: 0), animated: true)

下面控制器滑动时候

在scrollViewDidScroll里面判断左滑右滑,并判断进度,把信息传递给上面.

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if scrollView.contentOffset.x == startOffsetX || isForbidDelegate { return }
    // 1.定义目标的index、进度
    var targetIndex : Int = 0
    var progress : CGFloat = 0
    // 2.判断用户是左滑还是右滑
    if scrollView.contentOffset.x > startOffsetX { // 左滑 右移动
        targetIndex = Int(startOffsetX / scrollView.bounds.width) + 1
        if targetIndex >= childVcs.count {
            targetIndex = childVcs.count - 1
        }
        progress = (scrollView.contentOffset.x - startOffsetX) / scrollView.bounds.width
    } else { // 右滑
        targetIndex = Int(startOffsetX / scrollView.bounds.width) - 1
        if targetIndex < 0 {
            targetIndex = 0
        }
        progress = (startOffsetX - scrollView.contentOffset.x) / scrollView.bounds.width
    }
    // 3.将数据传递给titleView
    delegate?.contentView(self, targetIndex: targetIndex, progress: progress)
}}
快速滑动细节处理 如果开始拖拽时候下面view一页没滑动完毕,正在滑动,应计算他应该在哪里结束,让它滑动到它应该结束的地方,以此为其实值,要不会有上面标题底部条显示错乱
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
    // 记录开始的位置
    isForbidDelegate = false
    if Int(collectionView.contentOffset.x) % Int(collectionView.bounds.width) != 0  {
        let theNum = collectionView.contentOffset.x / collectionView.bounds.width
            let res = self.numFormat(num: Float(theNum ), format: "0")
            collectionView.scrollToItem(at: IndexPath(item: Int(res)!, section: 0), at: .left, animated: false)
            startOffsetX = collectionView.bounds.width*CGFloat(Float(res)!)
            delegate?.contentView(self, targetIndex:  Int(res)!, progress: 1)
            delegate?.contentView(self, endScroll:  Int(res)!)
    }else{
        startOffsetX = scrollView.contentOffset.x
    }
}

文字颜色渐变处理

文字颜色不能有透明度,要可以转成纯的rgb颜色才可以
在上面view里面接受到下面正在滑动中的progress时候,根据新旧两个index,取出两个头部label,设置颜色字体等

 func contentView(_ contentView: JDContentView, targetIndex: Int, progress: CGFloat) {
   if progress < 1 {
        self.isUserInteractionEnabled = false
    }else{
        self.isUserInteractionEnabled = true
    }
    // 1.取出两个Label
    let oldLabel = titleLabels[currentIndex]
    let newLabel = titleLabels[targetIndex]
// 2.渐变文字颜色
    let selectRGB = getGRBValue(style.selectColor)
    let normalRGB = getGRBValue(style.normalColor)
    let deltaRGB = (selectRGB.0 - normalRGB.0, selectRGB.1 - normalRGB.1, selectRGB.2 - normalRGB.2)
    oldLabel.textColor = UIColor(r: selectRGB.0 - deltaRGB.0 * progress, g: selectRGB.1 - deltaRGB.1 * progress, b: selectRGB.2 - deltaRGB.2 * progress)
    newLabel.textColor = UIColor(r: normalRGB.0 + deltaRGB.0 * progress, g: normalRGB.1 + deltaRGB.1 * progress, b: normalRGB.2 + deltaRGB.2 * progress)
    if progress > 0.5 {
        oldLabel.font = style.titleFont
        newLabel.font = style.selectedTitleFont
    }else{
        oldLabel.font = style.selectedTitleFont
        newLabel.font = style.titleFont
    }}
private func getGRBValue(_ color : UIColor) -> (CGFloat, CGFloat, CGFloat) {
    guard  let components = color.cgColor.components else {
        fatalError("文字颜色请按照RGB方式设置 颜色不能有透明度")
    }
    return (components[0] * 255, components[1] * 255, components[2] * 255)
}

相关文章

网友评论

      本文标题:swift 标题视图联动 颜色渐变 滚动条渐变

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