首页 > 系统 > iOS > 正文

iOS 页面滑动与标题切换颜色渐变的联动效果实例

2020-07-26 02:51:43
字体:
来源:转载
供稿:网友

话不多说,直接上图,要实现类似如下效果。

这个效果非常常见,这里着重讲讲核心代码

封装顶部的PageTitleView

封装构造函数

封装构造函数,让别人在创建对象时,就传入其实需要显示的内容 frame:创建对象时确定了

  1. frame就可以直接设置子控件的位置和尺寸
  2. isScrollEnable:是否可以滚动。某些地方该控件是可以滚动的。
  3. titles:显示的所有标题
// MARK:- 构造函数init(frame: CGRect, isScrollEnable : Bool, titles : [String]) {selfisScrollEnable = isScrollEnableselftitles = titlessuperinit(frame: frame)}

设置UI界面

设置UI界面

  1.  添加UIScrollView,如果标题过多,则可以滚动
  2. 初始化所有的Label,用于显示标题。并且给label添加监听手势
  3. 添加顶部线和滑块的View

实现相对来说比较简单,这里代码从略

封装底部的PageCotentView

封装构造函数

封装构造函数,让别人在创建对象时,就传入其实需要显示的内容

  1. 所有用于显示在UICollectionView的Cell的所有控制器
  2. 控制器的父控制器
// MARK:- 构造函数init(frame: CGRect, childVcs : [UIViewController], parentViewController : UIViewController) {selfchildVcs = childVcsselfparentViewController = parentViewControllersuperinit(frame: frame)}

设置UI界面内容

设置UI界面

  1. 将所有的子控制器添加到父控制器中
  2. 添加UICollectionView,用于展示内容
// MARK:- 懒加载属性private lazy var collectionView : UICollectionView = {// 1.创建布局let layout = UICollectionViewFlowLayout()layout.itemSize = self.bounds.sizelayout.minimumLineSpacing = 0layout.minimumInteritemSpacing = 0layout.scrollDirection = .Horizontal// 2.创建collectionViewlet collectionView = UICollectionView(frame: self.bounds, collectionViewLayout: layout)collectionView.showsHorizontalScrollIndicator = falsecollectionView.pagingEnabled = truecollectionView.bounces = falsecollectionView.scrollsToTop = falsecollectionView.dataSource = selfcollectionView.delegate = selfcollectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: kContentCellID)return collectionView}()private func setupUI() {// 1.添加所有的控制器for childVc in childVcs {parentViewController?.addChildViewController(childVc)}// 2.添加collectionViewaddSubview(collectionView)}

实现UICollectionView的数据源方法

  1. 在返回Cell的方法中,先将cell的contentView中的子控件都移除,防止循环引用
  2. 取出indexPath.item对应的控制器,将控制器的View添加到Cell的contentView中
// MARK:- 遵守UICollectionView的数据源extension PageContentView : UICollectionViewDataSource {func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {return childVcs.count}func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {let cell = collectionView.dequeueReusableCellWithReuseIdentifier(kContentCellID, forIndexPath: indexPath)// 移除之前的for subview in cell.contentView.subviews {subview.removeFromSuperview()}// 取出控制器let childVc = childVcs[indexPath.item]childVc.view.frame = cell.contentView.boundscell.contentView.addSubview(childVc.view)return cell}}

PageTitleView点击改变PageContentView

通过代理将PageTitleView的事件传递出去

/// 定义协议protocol PageTitleViewDelegate : class {func pageTitleView(pageTitleView : PageTitleView, didSelectedIndex index : Int)}@objc private func titleLabelClick(tapGes : UITapGestureRecognizer) {// 1.获取点击的下标志guard let view = tapGes.view else { return }let index = view.tag// 2.滚到正确的位置scrollToIndex(index)// 3.通知代理delegate?.pageTitleView(self, didSelectedIndex: index)}

内部调整

// 内容滚动private func scrollToIndex(index : Int) {// 1.获取最新的label和之前的labellet newLabel = titleLabels[index]let oldLabel = titleLabels[currentIndex]// 2.设置label的颜色newLabel.textColor = kSelectTitleColoroldLabel.textColor = kNormalTitleColor// 3.scrollLine滚到正确的位置let scrollLineEndX = scrollLine.frame.width * CGFloat(index)UIView.animateWithDuration(0.15) {self.scrollLine.frame.origin.x = scrollLineEndX}// 4.记录indexcurrentIndex = index}

在PageContentView中设置当前应该滚动的位置

// MARK:- 对外暴露方法extension PageContentView { func scrollToIndex(index : Int) {let offset = CGPoint(x: CGFloat(index) * collectionViewboundswidth, y: 0) collectionViewsetContentOffset(offset, animated: false)}}

PageContentView滚动调整PageTitleView

通过观察,我们发现:

                1> 原来位置的Title颜色会逐渐变暗

                2> 目标位置的Title颜色会逐渐变亮

                3> 变化程度是和滚动的多少相关

由此得出结论:

我们一共需要获取三个值

1> 起始位置下标值

2> 目标位置下标值

3> 当前滚动的进度

其实前2点可以由第3点计算而来,可以只需要将进度传递出去。

根据进度值处理标题颜色渐变及滑块逻辑

         。当前进度值唯一确定了标题的状态,计算出需要发生颜色变化的两相邻标题索引

         。注意:下标值需要防止越界问题,临界点的处理

实现代码

extension PageContentView : UICollectionViewDelegate {func scrollViewWillBeginDragging(scrollView: UIScrollView) {startOffsetX = scrollView.contentOffset.x}func scrollViewDidScroll(scrollView: UIScrollView) {// 0.判断是否是点击事件 if isForbidScrollDelegate { return }// 1.定义获取需要的数据 var progress : CGFloat = 0 let currentOffsetX = scrollView.contentOffset.x let scrollViewW = scrollView.bounds.width  // 1.计算progress  progress = currentOffsetX / scrollViewW  // 3.将progress传递给titleView delegate?.pageContentView(self, progress: progress) }}

根据滚动传入的值,调整PageTitleView

两种颜色必须使用RGB值设置(方便通过RGB实现渐变效果)

private let kNormalRGB : (CGFloat, CGFloat, CGFloat) = (85, 85, 85)private let kSelectRGB : (CGFloat, CGFloat, CGFloat) = (255, 128, 0)private let kDeltaRGB = (kSelectRGB.0 - kNormalRGB.0, kSelectRGB.1 - kNormalRGB.1, kSelectRGB.2 - kNormalRGB.2)private let kNormalTitleColor = UIColor(red: 85/255.0, green: 85/255.0, blue: 85/255.0, alpha: 1.0)private let kSelectTitleColor = UIColor(red: 255.0/255.0, green: 128/255.0, blue: 0/255.0, alpha: 1.0)

调整scrollLine及两个Label颜色渐变

// MARK:- 对外暴露方法extension PageTitleView func changeLabel(progress: CGFloat) {// 开启弹簧效果时的过滤处理 var progress = progress > 0 ? progress : 0  progress = progress <= CGFloat(titleLabels.count - 1) ? progress : CGFloat(titleLabels.count - 1) var leftLabelIndex = Int(floor(progress)) let ratio = progress - CGFloat(leftLabelIndex) //获取leftLabel和rightLabel let leftLabel = titleLabels[leftLabelIndex] if leftLabelIndex >= 3{  leftLabelIndex = 3 } print("leftLabelIndex = /(leftLabelIndex)") var rightIndex = leftLabelIndex + 1 if rightIndex >= 3{  rightIndex = 3 } print("rightIndex = /(rightIndex)") let rightLabel = titleLabels[rightIndex] //滑块的逻辑 let moveTotalX = leftLabel.frame.width let moveX = moveTotalX * ratio scrollLine.frame.origin.x = leftLabel.frame.origin.x + moveX //3.Label颜色的渐变 // 3.1.取出变化的范围 let colorDelta = (kSelectedColor.0 - kNormalColor.0, kSelectedColor.1 - kNormalColor.1, kSelectedColor.2 - kNormalColor.2) if leftLabelIndex != rightIndex { // 3.2.变化leftLabel leftLabel.textColor = UIColor(r: kSelectedColor.0 - colorDelta.0 * ratio, g: kSelectedColor.1 - colorDelta.1 * ratio, b: kSelectedColor.2 - colorDelta.2 * ratio) // 3.2.变化rightLabel rightLabel.textColor = UIColor(r: kNormalColor.0 + colorDelta.0 * ratio, g: kNormalColor.1 + colorDelta.1 * ratio, b: kNormalColor.2 + colorDelta.2 * ratio) } // 4.记录最新的index currentIndex = leftLabelIndex }}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表