滑動(dòng)菜單欄的制作

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

2016-05-16 17_49_45.gif

首先寫一個(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)的位置而變化

799C2C2F-3C8F-4643-B7F5-BE4CE606529D.png
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

下載地址 https://github.com/lvjiaqijiaqi/CategoryBar

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 內(nèi)容抽屜菜單ListViewWebViewSwitchButton按鈕點(diǎn)贊按鈕進(jìn)度條TabLayout圖標(biāo)下拉刷新...
    皇小弟閱讀 47,133評(píng)論 22 665
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,050評(píng)論 4 61
  • p2p十大平臺(tái)_華融道理財(cái) p2p十大平臺(tái)_華融道理財(cái) p2p十大平臺(tái)_華融道理財(cái)
    米匠炕63561閱讀 189評(píng)論 0 0
  • //1,今天要求設(shè)置collectionView 大小不同本來想自定義 UICollectionViewLayou...
    貝灬小暉閱讀 146評(píng)論 0 0
  • 站在陌生的中學(xué)藍(lán)球場,三五個(gè)初中生 三四個(gè)大學(xué)生,他們各自組隊(duì)打籃球,我們在一旁看著,逗逗一旁特別可愛的三四歲的小...
    微妮安閱讀 206評(píng)論 2 2

友情鏈接更多精彩內(nèi)容