前言
最近自己參考了一些源碼寫了一個標簽頁,並把他傳到了CocoaPods上。大家可以集成到項目中進行使用,也可以看看源碼自己寫一個更好的,也希望如果有什麼意見可以告訴我,我會進行完善,項目地址:https://github.com/cbsfly/CBSSegmentView。
成果
自己寫了兩種形式的Demo,一種類似網易雲音樂的固定的標簽欄,一種是類似愛奇藝、今日頭條的可滾動的標簽欄。一開始只是草草的寫,後來經過師傅提醒考慮了下優化,只有移動到那個頁面才會對ViewController進行加載,這樣即使是很復雜的頁面很多網絡請求數據加載應該也不會有卡頓的現象。
如果有想加入項目中使用的同學可以利用CocoaPods,具體使用我放在github上了,歡迎使用。也可以把github上的zip直接下載下來看使用方法。接下來簡單介紹下實現原理。
實現原理
簡單的說,頂部的標簽欄是UIScrollView,底下也是一個UIScrollView,將多個`ViewController.view`初始化加入到下面ScrollView中的合適位置,並且與頂部的標簽欄相關聯,並且給上面的標簽欄增加點擊事件控制下部分的ScrollView可以移動到合適的位置就行了!
部分源碼解析
感覺其實沒什麼難點,比較需要動腦筋的實現應該就是頂部標簽欄隨下面ScrollView的滑動,包括字體顏色,下劃線移動。我就對這一部分進行介紹,對其他地方感興趣的同學可以自己把源碼下載下來看看。
這裡先上代碼,先上頂部標簽欄的初始化方法。這一部分比較繁瑣,肯定可以簡化代碼,時間有點緊就沒做了。
- (void)addScrollHeader:(NSArray *)titleArray { self.headerView.frame = CGRectMake(0, 0, self.width, self.buttonHeight); self.headerView.contentSize = CGSizeMake(self.buttonWidth*titleArray.count, self.buttonHeight); [self addSubview:self.headerView]; for (NSInteger index = 0; index < titleArray.count; index++) { _titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.buttonWidth*index, 0, self.buttonWidth, self.buttonHeight)]; _titleLabel.textColor = [UIColor blackColor]; _titleLabel.text = titleArray[index]; _titleLabel.textAlignment = NSTextAlignmentCenter; _titleLabel.adjustsFontSizeToFitWidth = YES; [self.headerView addSubview:_titleLabel]; _segmentBtn = [[UIButton alloc] initWithFrame:CGRectMake(self.buttonWidth*index, 0, self.buttonWidth, self.buttonHeight)]; _segmentBtn.tag = index; [_segmentBtn setBackgroundColor:[UIColor clearColor]]; [_segmentBtn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside]; [self.headerView addSubview:_segmentBtn]; } self.headerSelectedSuperView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.buttonWidth, self.buttonHeight)]; [self.headerView addSubview:self.headerSelectedSuperView]; self.headerSelectedView.frame =CGRectMake(0, 0, self.buttonWidth, self.buttonHeight); self.headerSelectedView.contentSize = CGSizeMake(self.buttonWidth*titleArray.count, self.buttonHeight); [self.headerSelectedSuperView addSubview:self.headerSelectedView]; for (NSInteger index = 0; index < titleArray.count; index++) { _titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.buttonWidth*index, 0, self.buttonWidth, self.buttonHeight)]; _titleLabel.textColor = [UIColor blueColor]; _titleLabel.text = titleArray[index]; _titleLabel.textAlignment = NSTextAlignmentCenter; _titleLabel.adjustsFontSizeToFitWidth = YES; [self.headerSelectedView addSubview:_titleLabel]; } UIImageView *bottomLine = [[UIImageView alloc] initWithFrame:CGRectMake(0, self.headerSelectedView.contentSize.height - self.lineHeight, self.headerSelectedView.contentSize.width, self.lineHeight)]; bottomLine.backgroundColor = [UIColor blueColor]; [self.headerSelectedView addSubview:bottomLine]; }
這裡的實現主要分成三個步驟,一開始在頂部加上一個`self.headerView`,這是一個UIScrollView,他是標簽欄視圖的最底層,所以需要最先add上去。在`self.headerView`我們會加上若干個UILabel,這幾個UILabel就是沒選中時的標簽樣子,就是上文gif中黑色的標簽。然後再加上若干個透明的Button方便添加點擊事件,當然也可以用手勢這裡隨意。
第二步就是加一個UIView的“父視圖”`self.headerSelectedSuperView`,這個父視圖的作用稍後說。
第三步就是再加上一個UIScrollView`self.headerSelectedView`,這是當前選中標簽應該展現的外觀的ScrollView,我們在這個ScrollView裡加入若干個UILabel,不同的是顏色要設置成選中標簽後的顏色,這裡我設置的是藍色。為了美觀,還加了一個藍色的下劃線。第三步有個關健就是將` _headerSelectedView.clipsToBounds = YES;`這個代碼我在headerSelectedView的get方法裡面寫了。這個屬性是說子視圖如果比父視圖大,則將超出的部分去掉,默認是NO的。不是很理解的最好取谷歌下,這個屬性是實現上圖效果的關健。
然後看UIScrollView的代理方法。
- (void)scrollViewDidScroll:(UIScrollView *)scrollView { if (scrollView == _backView) { self.headerSelectedSuperView.frame = CGRectMake(scrollView.contentOffset.x * (self.buttonWidth/self.width), self.headerSelectedSuperView.frame.origin.y, self.headerSelectedSuperView.frame.size.width, self.headerSelectedSuperView.frame.size.height); self.headerSelectedView.contentOffset = CGPointMake(scrollView.contentOffset.x * (self.buttonWidth/self.width), 0); } }
backView就是下面ViewController存放的ScrollView,當backView滾動時,我們需要改變標簽欄headerSelectedSuperView的frame和headerSelectedView的contentOffset,這樣的結果就是headerSelectedSuperView能移動到合適的位置,並且展示出headerSelectedSuperView子視圖也就是headerSelectedView合適的部分。這樣就能有gif中標簽欄的那種滾動效果了。這裡就和` _headerSelectedView.clipsToBounds = YES;`息息相關了。代碼很簡單。
至於其他部分我就不一一解析了,還是推薦大家看看源碼,也希望有什麼意見可以告訴我,互相提高互相進步。