话不多说,直接上图,要实现类似如下效果。
这个效果非常常见,这里着重讲讲核心代码
封装顶部的PageTitleView
封装构造函数
封装构造函数,让别人在创建对象时,就传入其实需要显示的内容 frame:创建对象时确定了
// MARK:- 构造函数 init(frame: CGRect, isScrollEnable : Bool, titles : [String]) { selfisScrollEnable = isScrollEnable selftitles = titles superinit(frame: frame) }
设置UI界面
设置UI界面
实现相对来说比较简单,这里代码从略
封装底部的PageCotentView
封装构造函数
封装构造函数,让别人在创建对象时,就传入其实需要显示的内容
// MARK:- 构造函数 init(frame: CGRect, childVcs : [UIViewController], parentViewController : UIViewController) { selfchildVcs = childVcs selfparentViewController = parentViewController superinit(frame: frame) }
设置UI界面内容
设置UI界面
// MARK:- 懒加载属性 private lazy var collectionView : UICollectionView = { // 1.创建布局 let layout = UICollectionViewFlowLayout() layout.itemSize = self.bounds.size layout.minimumLineSpacing = 0 layout.minimumInteritemSpacing = 0 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的数据源方法
// 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) * 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 } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
本文向大家介绍Unity3D实现渐变颜色效果,包括了Unity3D实现渐变颜色效果的使用技巧和注意事项,需要的朋友参考一下 基于unity3D实现渐变颜色的简单脚本,代码很少,就不废话了,直接上代码和效果图。 效果图: 虽然支持的内容不多,但是小而精,希望对大家有用。 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。
Vue 提供了多种方式支持动画过渡效果。例如在各个过渡阶段应用 CSS 类,提供钩子函数使用 JS 操作 DOM,使用第三方 CSS/JS 动画库等。 如果对 Vue 中内置的 transition 机制还不了解,可以阅读 官方的介绍。 在模板项目中,主要使用了最简单的应用 CSS 类的方式完成动画效果。 具体实现 在模板项目中,页面切换时,会有左右滑动效果。 具体表现为打开新页面时左滑展示,返回
本文向大家介绍Android实现页面滑动切换动画,包括了Android实现页面滑动切换动画的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了Android实现页面滑动切换动画的具体代码,供大家参考,具体内容如下 实现两个页面滑动切换,一些相册的效果也是如此 一个Activity的界面配置文件 activity_main.xml: MainActivity.java: 在res/anim
本文向大家介绍js实现的鼠标滚轮滚动切换页面效果(类似360默认页面滚动切换效果),包括了js实现的鼠标滚轮滚动切换页面效果(类似360默认页面滚动切换效果)的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了js实现的鼠标滚轮滚动切换页面效果的方法。分享给大家供大家参考,具体如下: 运行效果截图如下: 具体代码如下: 更多关于jQuery特效相关内容感兴趣的读者可查看本站专题:《jQuery
问题内容: 我在React Native应用程序中使用React Navigation,我想将标头更改为渐变,我发现这里有一个节点模块:在react native中实现渐变。 我有这样的Root StackNavigator : 我可以像这样包装或渐变: 如何将标题背景包装在中以使用该模块? 我知道我可以创建一个自定义标头组件并使用它,但是当我这样做时,React Navigation的所有本机导
本文向大家介绍和黑夜自动切换页面的颜色?相关面试题,主要包含被问及和黑夜自动切换页面的颜色?时的应答技巧和注意事项,需要的朋友参考一下 需要借助js才能在白天和黑夜中切换吧 媒体查询的内容都是设备的属性:宽度高度,旋转方向,打印样式,分辨率 所以用媒体查询的话,需要用户的设备拥有切换黑暗模式的功能 借助 js 切换页面颜色的话,那就是 获取地理位置 查询日出日落时间 根据时间修改全局 theme