自己寫了一個(gè)滑動(dòng)菜單欄,用了scrollView,感覺非常的簡單效果也還行,先上效果圖

首先寫一個(gè)UISCrollview的子類 , 用一個(gè)數(shù)組來保存需要展示的UIVIEWS和標(biāo)題
var viewTitles:[String]?
var viewItems:[UIView]?
在uiscroll滑動(dòng)的時(shí)候,會(huì)不停的調(diào)用layoutsubviews,我們在這里面去添加和刪除視圖。displayViewArr中保存著當(dāng)前顯示的view的索引
通過計(jì)算當(dāng)前應(yīng)該出現(xiàn)在屏幕上的視圖索引和已經(jīng)出現(xiàn)視圖索引的差集,來判斷哪些視圖應(yīng)該添加和刪除,還可以添加一個(gè)fadeIn-out的效果
var displayViewArr:Set<Int> = []
internal override func layoutSubviews() {
let Xoffset = self.contentOffset.x
let preIndex = Int(floor(Xoffset/self.itemWidth))
var displaySets:Set<Int> = [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<Int> = displaySets.subtract(self.displayViewArr) //應(yīng)該添加的視圖
for x in shouldAddToViews {
self.addSubview((self.viewItems?[x])!)
}
let shouldRemoveToViews:Set<Int> = self.displayViewArr.subtract(displaySets) //應(yīng)該刪除的視圖
for x in shouldRemoveToViews {
self.viewItems?[x].removeFromSuperview()
}
self.displayViewArr = displaySets
}
接下來是滑塊上面控件的制作,關(guān)鍵是上面的滑動(dòng)效果,樓主采用了maskView去做的效果,最上面的一層文字層做maskView,這樣文字的顏色就會(huì)跟著下面底層VIew的顏色而變化,底層的顏色是藍(lán)色,在底層View上面有一個(gè)游標(biāo)的View,是粉色的當(dāng)滑動(dòng)粉色游標(biāo)View的時(shí)候,,上面文字的顏色也就會(huì)隨著游標(biāo)的位置而變化

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)
}
}
接下來是監(jiān)聽contentOffset的變化,這里有兩個(gè)地方會(huì)隨著變化,一個(gè)是headerView的frame和bounds,另外一個(gè)就是游標(biāo)的Frame,
在observeValueForKeyPath中改變headerView和游標(biāo)View的frame , updatePosition函數(shù)中改變headView的bonds保證所選的item的標(biāo)簽一直在view'的中間。
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
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
}
}
接下來是點(diǎn)擊事件 這個(gè)比較簡單
override func touchesBegan(touches: Set<UITouch>, 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)
}
}
}
寫一個(gè)便利構(gòu)造器初始化我們的bar控件,scrollview的pagingEnabled幫了我們很大的忙,用一下就知道了,整頁翻動(dòng)。
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()
}
接下來在控制器中調(diào)用就行了,調(diào)用很簡單傳一個(gè)view數(shù)組和title數(shù)組
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