iOS 滑动页面标题切换颜色渐变效果
话不多说,直接上图,要实现类似如下效果。
- 这个效果非常常见,这里着重讲讲核心代码

封装顶部的PageTitleView
封装构造函数
- 封装构造函数,让别人在创建对象时,就传入其实需要显示的内容
- frame:创建对象时确定了frame就可以直接设置子控件的位置和尺寸
- isScrollEnable:是否可以滚动。某些地方该控件是可以滚动的。
- titles:显示的所有标题
// MARK:- 构造函数init(frame: CGRect, isScrollEnable : Bool, titles : [String]) {self.isScrollEnable = isScrollEnableself.titles = titlessuper.init(frame: frame)}
设置UI界面
- 设置UI界面
- 添加UIScrollView,如果标题过多,则可以滚动
- 初始化所有的Label,用于显示标题。并且给label添加监听手势
- 添加顶部线和滑块的View
实现相对来说比较简单,这里代码从略
封装底部的PageCotentView
封装构造函数
- 封装构造函数,让别人在创建对象时,就传入其实需要显示的内容
- 所有用于显示在UICollectionView的Cell的所有控制器
- 控制器的父控制器
// MARK:- 构造函数init(frame: CGRect, childVcs : [UIViewController], parentViewController : UIViewController) {self.childVcs = childVcsself.parentViewController = parentViewControllersuper.init(frame: frame)}
设置UI界面内容
- 设置UI界面
- 将所有的子控制器添加到父控制器中
- 添加UICollectionView,用于展示内容
// MARK:- 懒加载属性
private lazy var collectionView : UICollectionView = {
// 1.创建布局
let layout = UICollectionViewFlowLayout()
layout.itemSize = self.bounds.size
layout.minimumLineSpacing =
layout.minimumInteritemSpacing =
layout.scrollDirection = .Horizontal
// 2.创建collectionView
let collectionView = UICollectionView(frame: self.bounds, collectionViewLayout: layout)
collectionView.showsHorizontalScrollIndicator = false
collectionView.pagingEnabled = true
collectionView.bounces = false
collectionView.scrollsToTop = false
collectionView.dataSource = self
collectionView.delegate = self
collectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: kContentCellID)
return collectionView
}()
private func setupUI() {
// 1.添加所有的控制器
for childVc in childVcs {
parentViewController?.addChildViewController(childVc)
}
// 2.添加collectionView
addSubview(collectionView)
}
实现UICollectionView的数据源方法
- 在返回Cell的方法中,先将cell的contentView中的子控件都移除,防止循环引用
- 取出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.bounds
cell.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和之前的label
let newLabel = titleLabels[index]
let oldLabel = titleLabels[currentIndex]
// 2.设置label的颜色
newLabel.textColor = kSelectTitleColor
oldLabel.textColor = kNormalTitleColor
// 3.scrollLine滚到正确的位置
let scrollLineEndX = scrollLine.frame.width * CGFloat(index)
UIView.animateWithDuration(0.15) {
self.scrollLine.frame.origin.x = scrollLineEndX
}
// 4.记录index
currentIndex = index
}
- 在PageContentView中设置当前应该滚动的位置
// MARK:- 对外暴露方法extension PageContentView {func scrollToIndex(index : Int) {let offset = CGPoint(x: CGFloat(index) * collectionView.bounds.width, y: 0)collectionView.setContentOffset(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 =
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 > ? progress :
progress = progress <= CGFloat(titleLabels.count - ) ? progress : CGFloat(titleLabels.count - )
var leftLabelIndex = Int(floor(progress))
let ratio = progress - CGFloat(leftLabelIndex)
//获取leftLabel和rightLabel
let leftLabel = titleLabels[leftLabelIndex]
if leftLabelIndex >= {
leftLabelIndex =
}
print("leftLabelIndex = \(leftLabelIndex)")
var rightIndex = leftLabelIndex +
if rightIndex >= {
rightIndex =
}
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. - kNormalColor., kSelectedColor. - kNormalColor., kSelectedColor. - kNormalColor.)
if leftLabelIndex != rightIndex {
// 3.2.变化leftLabel
leftLabel.textColor = UIColor(r: kSelectedColor. - colorDelta. * ratio, g: kSelectedColor. - colorDelta. * ratio, b: kSelectedColor. - colorDelta. * ratio)
// 3.2.变化rightLabel
rightLabel.textColor = UIColor(r: kNormalColor. + colorDelta. * ratio, g: kNormalColor. + colorDelta. * ratio, b: kNormalColor. + colorDelta. * ratio)
}
// 4.记录最新的index
currentIndex = leftLabelIndex
}
}
iOS 滑动页面标题切换颜色渐变效果的更多相关文章
- Selenium WebDriver-通过页面标题切换窗口
selenium webdriver可以通过获取页面标题,再跟据标题去切换浏览器窗口,代码如下: #encoding=utf-8 import unittest import time import ...
- 解决IOS滑动页面fixed浮动问题
<div style="position: fixed"></div> <div style="height: 100%; overflow ...
- 在uwp仿IOS的页面切换效果
有时候我们需要编写一些迎合IOS用户使用习惯的uwp应用,我在这里整理一下仿IOS页面切换效果的代码. 先分析IOS的页面切换.用户使用左右滑动方式进行前进和后退,播放类似于FlipView的切换动画 ...
- Android之怎样实现滑动页面切换【Fragment】
Fragment 页面切换不能滑动 所以对于listview 能够加入的左右滑动事件 .不会有冲突比如(QQ的好友列表的删除) Fragment 和viewpager 的差别 Viewpager ...
- bootsrtap h5 移动版页面 在苹果手机ios滑动上下拉动滚动卡顿问题解决方法
bootsrtap h5 移动版页面 在苹果手机ios滑动上下拉动滚动卡顿问题解决方法 bootsrtap框架做的h5页面,在android手机下没有卡顿问题,在苹果手机就一直存在这问题,开始毫无头绪 ...
- ViewPager+PagerTabStrip实现页面的切换
页面切换效果图 首先创建布局: 代码: <?xml version="1.0" encoding="utf-8"?><LinearLayout ...
- iOS开发系列--视图切换
概述 在iOS开发中视图的切换是很频繁的,独立的视图应用在实际开发过程中并不常见,除非你的应用足够简单.在iOS开发中常用的视图切换有三种,今天我们将一一介绍: UITabBarController ...
- Visual Studio跨平台开发实战(3) - Xamarin iOS多页面应用程式开发
原文 Visual Studio跨平台开发实战(3) - Xamarin iOS多页面应用程式开发 前言 在前一篇教学中, 我们学会如何使用Visual Studio 搭配Xcode 进行iOS基本控 ...
- ViewPager和View组合 实现页面的切换
//--------------主页面------------------------------- package com.bw.test; import java.util.ArrayList;i ...
随机推荐
- nodejs中异步
nodejs中的异步 1 nodejs 中的异步存在吗? 现在有点 javascript 基础的人都在听说过 nodejs ,而只要与 javascript 打交到人都会用或者是将要使用 nodejs ...
- PC端Web项目开发流程
从前一直再做前端,突然想到如果有一天领导让自己独立承担一个web 项目的话是否有足够的能力去接这个任务,要学会自己去搭建一些基础的工具信息.所有的这一切在心里都要有个大致的流程,不然真正做的时候难免会 ...
- 每天一个linux命令(34)--top命令
今天给领导发邮件,我这边虽然显示发出去了,但是他那边一直没收到,结果我以为我发了,他又一直在那边等结果.所以说,以后要另外发个信息或者QQ微信之类的说一声. top命令是Linux 下常用的性能分析工 ...
- SpringMvc的运行流程
一.先用文字描述 1.用户发送请求到DispatchServlet 2.DispatchServlet根据请求路径查询具体的Handler 3.HandlerMapping返回一个HandlerExc ...
- 前端资讯周报 2.27 - 3.5: 如何设计一个优秀的HTML接口,深入理解line-height
从本周起,每周一我都会分享上一周我订阅的技术站点中,和解决问题的过程中阅读到的值得分享的文章,或者视频教程,又或者图书. 个人认为国外的技术文章质量较高,而且发布的技术资讯也走在行业前沿,所以比较关注 ...
- solr6.4.1搜索引擎同步mysql数据库
尚未成功启动solr的,请参考我的另一篇文章:http://www.cnblogs.com/zhuwenjoyce/p/6506359.html(solr6.4.1 搜索引擎启动eclipse启动) ...
- String类的indexOf方法的用法和举例
2017年3月3号博主第一次去郑州互联网公司面试,背景是这样的我先前去了农大龙子湖校园招聘投简历,然后第二天去面试了那经历可以说是很失败的一次面试,当然这跟自己的水平有关了接下来重点讲一下面试的题目: ...
- synchronized和lock比对
前言:在上面的博客说了synchronized的一些用法,下面我们再来看看lock,这个出现频率也是非常高的一个. 1:获取Lock锁的几种方式 前面说了synchronized有锁对象和锁类对象,当 ...
- Java设计模式之职责型模式总结
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6548127.html 所谓职责型模式,就是采用各种模式来分配各个类的职责. 职责型模式包括 ...
- Android7.0 Phone应用源码分析(四) phone挂断流程分析
电话挂断分为本地挂断和远程挂断,下面我们就针对这两种情况各做分析 先来看下本地挂断电话的时序图: 步骤1:点击通话界面的挂断按钮,会调用到CallCardPresenter的endCallClicke ...