前几天翻手机的时候,被UC浏览器的一个小细节吸引,就是上方的一个滚动栏,他的细节是什么,估计可以打开UC浏览器或者看完下面的描述会有所了解,刚开始会觉得很简单,但在即将结束的时候,还是感觉自己太天真了,具体的细节请看下面的模拟图
代码的GitHub:https://github.com/YRunIntoLove/YSimalilarScrollView
在真正介绍代码之前,我想先说一下思路,因为个人觉得,思路或者想法比代码重要的多,这个表现是应用了一个叫做视错觉的原理,就是让人的眼睛相信这是真的,实际却不是真的,具体的解释请百度一下视错觉就会出现很明确的解释,说一下具体的思路:
1、首先需要在底层铺上一个滚动视图(UIScrollView),记做bottomScrollView,相信这个肯定也都看得出来,毕竟滚动嘛
2、在滚动视图(bottomScrollView)上再铺上原始标签,也就是后面的显示Hello、Objective-C(- - Demo上写错了)的标签
3、需要创建一个用来标注选择的视图,记做showChooseView,也就是Demo中的那个红色的块状视图
4、核心的步骤,创建一个存放选中后标签的视图,也就是存放Demo中白色字体标签的视图,记做showSelectView.
5、将标签按照2中之前原始标签的frame依次铺到showSelectView中
6、将创建好的showSelectView视图铺到showChooseView中,记得将showChooseView.clipsToBounds = true,为的是将5中视图超出showChooseView的部分隐藏不显示
7、为了响应点击事件,在1中的滚动视图上添加button,颜色设置为透明色,添加点击事件即可
8、在变化showChooseView的frame同时改变showSelectView的frame,让人感觉是颜色发生了变化,实际是是视图间进行了覆盖
原理明白之后,这个Demo就非常好做了。首先创建一个名字叫做YSimailarScrollView的类
设置了如下属性
//
// YSimailarScrollView.swift
// SimilarUCScrollDemo
//
// Created by YueWen on 16/3/4.
// Copyright © 2016年 YueWen. All rights reserved.
//
import UIKit
typealias ScrollBlock = (scale : Int) -> Void
/// 上端的滚动状态栏
class YSimailarScrollView: UIView {
var bottomScrollView:UIScrollView! //底层负责滚动的滚动视图
var showChooseView:UIView! //负责显示选中的视图
var showSelectView:UIView! //展示背后存放的视图
var backTitleColor = UIColor.blackColor() //底层展示文字颜色
var showTitleColor = UIColor.whiteColor() //选中展示文字颜色
var showBackColor = UIColor.redColor() //选中视图的背景色
var fontSize = 16.0 //文字的大小
var duration = 0.5 //动画完成的时间
var numberOfTitle = 4 //每页呈现的个数
var sHeight:CGFloat = 40.0 //状态栏的高度
//数据变量
var width : CGFloat?
var labels : [UILabel]?
var titles : [String] = ["Run","Into","Love","Yue"]
var scrollBlockHandle:ScrollBlock? //点击进行的回调
重写父类的init方法
//MARK: - 重写父类的方法
override init(frame: CGRect)
{
//初始化视图
bottomScrollView = UIScrollView()
showSelectView = UIView()
showChooseView = UIView()
//初始化数组
labels = Array()
width = frame.size.width / CGFloat(numberOfTitle)
super.init(frame: frame)
}
然后需要创建各个视图
1、bottomScrollView
/**
创建底层的滚动视图
*/
func yBottomScrollView()
{
bottomScrollView.frame = self.bounds
bottomScrollView.contentSize = CGSize(width: width! * CGFloat(titles.count),height: sHeight)
bottomScrollView.showsHorizontalScrollIndicator = false
self.addSubview(bottomScrollView)
}
2、在bottomScrollView中铺上底层标签
/**
创建底层的标签
*/
func createBottomLabel()
{
for(var i = 0; i < titles.count; i++)
{
let label = createLabel(i, titleColor: backTitleColor)
bottomScrollView.addSubview(label)
}
}
3、创建标注视图showChooseView
/**
创建选中的视图
*/
func yShowChooseView()
{
showChooseView.frame = frameOfView(0)
showChooseView.backgroundColor = showBackColor
showChooseView.clipsToBounds = true
bottomScrollView.addSubview(showChooseView)
}
4、创建showSelectView并将选中后显示的label铺到视图上
/**
创建展示背后存放的视图
*/
func yShowSelectView()
{
showSelectView.frame = bottomScrollView.bounds
for(var i = 0; i < titles.count; i++)
{
showSelectView.addSubview(createLabel(i, titleColor: showTitleColor))
}
showChooseView.addSubview(showSelectView)
}
5、添加响应的按钮层
/**
创建响应的按钮
*/
func createResponseButton()
{
for(var i = 0; i < titles.count; i++)
{
let button = createButton(i)
bottomScrollView.addSubview(button)
}
}
6、下面是一些自定义的方法
6.1、便利创建标签的方法
/**
根据索引创建Label对象
:param: index 索引
:param: titleColor 显示的文字颜色
:returns: 创建好的Label
*/
func createLabel(index : NSInteger, titleColor : UIColor) -> UILabel
{
let frame = CGRectMake((CGFloat(index)) * width!, 0, width!, sHeight)
let label = UILabel(frame: frame)
label.textAlignment = NSTextAlignment.Center
label.font = UIFont.systemFontOfSize(CGFloat(fontSize))
label.textColor = titleColor
label.text = titles[index]
labels?.append(label)//添加到数组
return label
}
6.2.1、便利创建按钮的方法
/**
根据索引创建按钮对象
:param: index 索引
:returns: 当前标签的frame
*/
func createButton(index: NSInteger) -> UIButton
{
let button = UIButton(type: UIButtonType.Custom)
button.frame = frameOfView(index)
button.tag = index
button.backgroundColor = UIColor.clearColor()
button.addTarget(self, action: Selector("labelDidTap:"), forControlEvents: UIControlEvents.TouchUpInside)
return button
}
6.2.2、响应方法
/**
按钮点击的目标动作回调
:param: sender 回调的发送者
*/
func labelDidTap(sender : AnyObject)
{
//获取button
let button = sender as! UIButton
//获取当前的frame
let frame = frameOfView(button.tag)
let frameSelect = handleFrame(frame)
//回调Block
scrollBlockHandle!(scale: Int(frame.origin.x / width!))
//设置frame
UIView.animateWithDuration(duration) { () -> Void in
self.showChooseView.frame = frame
self.showSelectView.frame = frameSelect
}
}
6.3、设置闭包
/**
设置闭包回调
:param: scrollBlockHandleNew 闭包回调
*/
func selectTapBlockHandle(scrollBlockHandleNew:ScrollBlock)
{
scrollBlockHandle = scrollBlockHandleNew
}
6.4、数据处理的方法
/**
处理当前的frame
:param: frame 需要处理的frame
:returns: 处理完毕的frame
*/
func handleFrame(frame : CGRect) -> CGRect
{
var frameHandle = frame
frameHandle.origin.x = -1 * frame.origin.x
return frameHandle
}
//MARK: - 对外接口
/**
滚动到当前偏移量的位置
:param: contentOff 滚动的偏移量
*/
func sliderSimailarScrollView(contentOff : CGPoint)
{
//获取当前选中视图的位置
var frame = showChooseView.frame
//对点进行处理
frame.origin.x = contentOff.x / CGFloat(numberOfTitle)
//动画执行
UIView.animateWithDuration(0.2) { () -> Void in
self.showChooseView.frame = frame
self.showSelectView.frame = self.handleFrame(frame)
}
}
来处理主要的ViewController.swift中的代码,没有太大的逻辑难度了,相信也都看得懂
//
// ViewController.swift
// SimilarUCScrollDemo
//
// Created by YueWen on 16/3/4.
// Copyright © 2016年 YueWen. All rights reserved.
//
import UIKit
class ViewController: UIViewController ,UIScrollViewDelegate{
var scrollView = UIScrollView()
var simailarScorllView:YSimailarScrollView!
override func viewDidLoad() {
super.viewDidLoad()
let titles = ["Hello","Objctive-C","Swift","C++","Java"]
//创建滚动视图对象
let frame = CGRectMake(0, 30, self.view.bounds.size.width, 40)
simailarScorllView = YSimailarScrollView(frame: frame)
//设置相关属性
simailarScorllView.titles = titles
self.view.addSubview(simailarScorllView)
simailarScorllView.selectTapBlockHandle { (scale) -> Void in
//开始滚动下方的滚动视图
self.scrollView.contentOffset = CGPoint(x: CGFloat(scale) * self.scrollView.bounds.size.width, y: 0)
}
//初始化滚动视图
scrollView.frame = CGRectMake(0, 70, self.view.bounds.size.width, self.view.bounds.size.height - 70)
scrollView.delegate = self;
scrollView.pagingEnabled = true
self.view.addSubview(scrollView)
//初始化五个视图
for(var i = 0; i < 5; i++)
{
scrollView.addSubview(createView(i, title: titles[i]))
}
scrollView.contentSize = CGSize(width: CGFloat(titles.count) * scrollView.bounds.size.width, height: scrollView.bounds.size.height)
self.view.backgroundColor = UIColor.cyanColor()
}
func createView(index : Int,title : String) -> UIView
{
let view = UIView(frame: CGRectMake(CGFloat(index) * scrollView.bounds.size.width,0,scrollView.bounds.size.width,scrollView.bounds.size.height))
let label = UILabel(frame: CGRectMake(10,20,150,30))
label.textColor = UIColor.purpleColor()
label.font = UIFont.systemFontOfSize(14)
label.text = "我是" + title
view.addSubview(label)
return view
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: - UIScrollView Delegate
func scrollViewDidScroll(scrollView: UIScrollView)
{
//获取当前的偏移量
let point = scrollView.contentOffset;
simailarScorllView.sliderSimailarScrollView(point)
}
}