自己写了一个滑动菜单栏,用了scrollView,感觉非常的简单效果也还行,先上效果图
首先写一个UISCrollview的子类 , 用一个数组来保存需要展示的UIVIEWS和标题
var viewTitles:[String]?
var viewItems:[UIView]?
在uiscroll滑动的时候,会不停的调用layoutsubviews,我们在这里面去添加和删除视图。displayViewArr中保存着当前显示的view的索引
通过计算当前应该出现在屏幕上的视图索引和已经出现视图索引的差集,来判断哪些视图应该添加和删除,还可以添加一个fadeIn-out的效果
var displayViewArr:Set = []
internal override func layoutSubviews() {
let Xoffset = self.contentOffset.x
let preIndex = Int(floor(Xoffset/self.itemWidth))
var displaySets:Set = [preIndex]
let scrollProgress = (Xoffset%self.itemWidth)/self.itemWidth
if scrollProgress != 0 {
displaySets.insert(preIndex+1)
self.viewItems?[preIndex].alpha = 1-scrollProgress
self.viewItems?[preIndex+1].alpha = scrollProgress
}else{
self.viewItems?[preIndex].alpha = 1
self.headerBarView?.updatePosition(preIndex+1)
}
let shouldAddToViews:Set = displaySets.subtract(self.displayViewArr) //应该添加的视图
for x in shouldAddToViews {
self.addSubview((self.viewItems?[x])!)
}
let shouldRemoveToViews:Set = self.displayViewArr.subtract(displaySets) //应该删除的视图
for x in shouldRemoveToViews {
self.viewItems?[x].removeFromSuperview()
}
self.displayViewArr = displaySets
}
接下来是滑块上面控件的制作,关键是上面的滑动效果,楼主采用了maskView去做的效果,最上面的一层文字层做maskView,这样文字的颜色就会跟着下面底层VIew的颜色而变化,底层的颜色是蓝色,在底层View上面有一个游标的View,是粉色的当滑动粉色游标View的时候,,上面文字的颜色也就会随着游标的位置而变化
func initConponent(){
self.frame.origin = CGPointZero
self.backgroundColor = CollectionViewBarConfig.HeaderBarBackgroundColor
let wordsMaskView:UIView = UIView(frame: CGRectMake(0, 0, self.frame.size.width, self.frame.size.height))
wordsMaskView.backgroundColor = UIColor(red: 0, green:0, blue: 0, alpha: 0.3)
self.items.reserveCapacity(self.itemsTitle.count)
for index:Int in 1...self.itemsTitle.count {
let label = UILabel()
label.frame = CGRectMake(self.itemWidth*(CGFloat(index)-1), 0, self.itemWidth, self.frame.size.height)
label.text = "\(self.itemsTitle[index-1])"
label.font = UIFont(name: "Arial", size: 16.0)
label.textAlignment = NSTextAlignment.Center
label.backgroundColor = UIColor.clearColor()
self.items.append(label)
wordsMaskView.addSubview(label)
}
self.maskView = wordsMaskView
self.swimmingView = UIView(frame: CGRectMake(0, 0, self.itemWidth, self.frame.size.height))
self.swimmingView?.backgroundColor = CollectionViewBarConfig.HeaderBarWordsColor
self.addSubview(self.swimmingView!)
if let scrollView = self.scrollView {
scrollView.addObserver(self, forKeyPath: "contentOffset", options: NSKeyValueObservingOptions.New, context: nil)
}
}
接下来是监听contentOffset的变化,这里有两个地方会随着变化,一个是headerView的frame和bounds,另外一个就是游标的Frame,
在observeValueForKeyPath中改变headerView和游标View的frame , updatePosition函数中改变headView的bonds保证所选的item的标签一直在view'的中间。
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer) {
if keyPath == "contentOffset" {
let offsetX = change!["new"]?.CGPointValue()
var origin = self.frame.origin
origin = CGPointMake((offsetX?.x)!, origin.y)
self.frame.origin = origin
let ratio = (offsetX?.x)!/(self.scrollView!.frame.size.width)
self.swimmingView!.frame.origin = CGPointMake(self.itemWidth*ratio, 0)
}
}
func updatePosition(index:Int){
if self.itemIndex == index { return }
self.itemIndex = index
let leftLimit:Int = Int(ceil(Double(CollectionViewBarConfig.HeaderBarItemNum)/2))
let rightLimit = self.itemsTitle.count-leftLimit+1
var offset:CGFloat = 0;
if index <= leftLimit {
offset = 0
}else if index >= rightLimit{
offset = self.itemWidth*(CGFloat(self.itemsTitle.count)-CGFloat(CollectionViewBarConfig.HeaderBarItemNum))
}else{
offset = self.itemWidth*CGFloat(index-leftLimit)
}
var origin = self.bounds.origin
origin.x = offset
UIView.animateWithDuration(0.4, delay: 0, options: UIViewAnimationOptions.CurveEaseOut, animations: {
self.bounds.origin = origin
}) { (true) in
}
}
接下来是点击事件 这个比较简单
override func touchesBegan(touches: Set, withEvent event: UIEvent?) {
if touches.count == 1 {
if let touch:UITouch = touches.first {
let Xoffset = touch.locationInView(self).x
let itemIndex = floor(Xoffset/self.itemWidth)
self.scrollView?.setContentOffset(CGPointMake(itemIndex*(self.scrollView?.frame.size.width)!, (self.scrollView?.contentOffset.y)! ), animated: false)
}
}
}
写一个便利构造器初始化我们的bar控件,scrollview的pagingEnabled帮了我们很大的忙,用一下就知道了,整页翻动。
convenience init(frame: CGRect , views:[UIView] , titles:[String]) {
self.init(frame: frame)
self.itemWidth = frame.size.width
self.bounces = false
self.delegate = self
self.directionalLockEnabled = true
self.pagingEnabled = true
self.viewTitles = titles
self.viewItems = views
self.initViews()
self.initHeaderView()
}
override init(frame: CGRect) {
super.init(frame: frame)
}
func initViews(){
for index in 0...self.viewItems!.count-1{
viewItems?[index].frame.origin = CGPointMake(self.itemWidth*CGFloat(index), CollectionViewBarConfig.HeaderBarHeight)
viewItems?[index].frame.size = CGSizeMake(self.frame.size.width, self.frame.size.height)
viewItems?[index].tag = index
}
displayViewArr.insert(0)
self.addSubview(viewItems![0])
self.contentSize = CGSizeMake(self.itemWidth*CGFloat(self.viewItems!.count), self.frame.size.height)
}
func initHeaderView(){
self.headerBarView = HeaderBarView()
self.headerBarView!.itemsTitle = self.viewTitles!
if viewItems!.count > CollectionViewBarConfig.HeaderBarItemNum {
self.headerBarView!.itemWidth = self.frame.size.width/CGFloat(CollectionViewBarConfig.HeaderBarItemNum)
}else {
self.headerBarView!.itemWidth = self.frame.size.width/CGFloat(viewItems!.count)
}
self.headerBarView!.frame = CGRectMake(0, 0, self.frame.size.width ,CollectionViewBarConfig.HeaderBarHeight)
self.headerBarView!.bounds = CGRectMake(0, 0, self.headerBarView!.itemWidth*CGFloat(viewItems!.count), CollectionViewBarConfig.HeaderBarHeight)
self.addSubview(self.headerBarView!)
self.headerBarView!.initConponent()
}
接下来在控制器中调用就行了,调用很简单传一个view数组和title数组
let v1:WaterMelonTV = WaterMelonTV(frame: CGRectMake(0, 0, self.view!.frame.size.width, self.view!.frame.size.height))
let v2:UIView = UIView(frame: CGRectMake(0, 0, self.view!.frame.size.width, self.view!.frame.size.height))
v2.backgroundColor = UIColor.greenColor()
let v3:UIView = UIView(frame: CGRectMake(0, 0, self.view!.frame.size.width, self.view!.frame.size.height))
v3.backgroundColor = UIColor.blueColor()
let v4:UIView = UIView(frame: CGRectMake(0, 0, self.view!.frame.size.width, self.view!.frame.size.height))
v4.backgroundColor = UIColor.brownColor()
let v5:UIView = UIView(frame: CGRectMake(0, 0, self.view!.frame.size.width, self.view!.frame.size.height))
v5.backgroundColor = UIColor.yellowColor()
let v6:UIView = UIView(frame: CGRectMake(0, 0, self.view!.frame.size.width, self.view!.frame.size.height))
v6.backgroundColor = UIColor.redColor()
let v7:UIView = UIView(frame: CGRectMake(0, 0, self.view!.frame.size.width, self.view!.frame.size.height))
v7.backgroundColor = UIColor.greenColor()
let v8:UIView = UIView(frame: CGRectMake(0, 0, self.view!.frame.size.width, self.view!.frame.size.height))
v8.backgroundColor = UIColor.blueColor()
let views:[UIView] = [v1,v2,v3,v4,v5,v6,v7,v8]
let titles:[String] = ["苹果","水蜜桃","菠萝","西瓜","橙子","蜜瓜","葡萄","芒果"]
let v:CategoryBar = CategoryBar(frame: CGRectMake(0, 0, self.view!.frame.size.width, self.view!.frame.size.height) , views:views , titles:titles)
self.view.addSubview(v)
self.categoryBar = v
下载地址 https://github.com/lvjiaqijiaqi/CategoryBar