最后的效果:
結構分析:該界面主要是有兩個UIScrollView組成踢关,上面的UIScrollView用于存放一組帶有點擊手勢的UILabel(也可以是按鈕)琢融,下面的UIScrollView用于顯示對面標題的UIViewController芋齿。
當點擊上面的UILabel(或UIButton)時扣草,下面的UIScrollView就移動到對應的位置顯示標題對應的UIController的內容谎僻。
/**
點擊上面的標題label
*/
- (void)respondsToTitleLabel:(UITapGestureRecognizer *)tapGR {
// 選中l(wèi)abel
[self selectedLabel:(UILabel *)tapGR.view];
// 顯示對應控制器的view
[self showContentVC:tapGR.view.tag - 200];
}
當滑動下面的UIScrollView顯示對應標題的內容時窒朋,上面的UIScrollView也移動到對應的位置,將該內容對應的UILabel(或UIButton)設為選中狀態(tài)腋粥。
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
// 獲取當前頁數(shù)
CGFloat currentPage = scrollView.contentOffset.x / SCREENWIDTH;
// 獲取當前選中l(wèi)abel
UILabel *currentSelectedLabel = [self.titleScrollView viewWithTag:200 + currentPage];
// 獲取上一個選中l(wèi)abel
UILabel *lastSelectedLabel;
if (currentPage + 1 < self.contentVCClassArray.count - 1) {
lastSelectedLabel = [self.titleScrollView viewWithTag:201 + currentPage];
}
// 計算上一個選中l(wèi)abel縮放比例
CGFloat lastSelectedLabelScale = currentPage - (NSInteger)currentPage;
// 計算當前選中l(wèi)abel縮放比例
CGFloat currentSelectedLabelScale = 1 - lastSelectedLabelScale;
// 縮放
currentSelectedLabel.transform = CGAffineTransformMakeScale(currentSelectedLabelScale * 0.3 + 1, currentSelectedLabelScale * 0.3 + 1);
lastSelectedLabel.transform = CGAffineTransformMakeScale(lastSelectedLabelScale * 0.3 + 1, lastSelectedLabelScale * 0.3 + 1);
// 顏色漸變
currentSelectedLabel.textColor = [UIColor colorWithRed:currentSelectedLabelScale green:0 blue:0 alpha:1];
lastSelectedLabel.textColor = [UIColor colorWithRed:lastSelectedLabelScale green:0 blue:0 alpha:1];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
// 選中l(wèi)abel
[self selectedLabel:(UILabel *)[self.titleScrollView viewWithTag:200 + scrollView.contentOffset.x / SCREENWIDTH]];
}
屬性介紹:
@property (nonatomic, weak) UILabel *currentSelectedTitleLabel; // 當前選中標題Label
@property (nonatomic, strong) UIScrollView *titleScrollView;
@property (nonatomic, strong) UIScrollView *contentScrollView;
@property (nonatomic, copy) NSArray *titleArray; // 標題數(shù)組
@property (nonatomic, copy) NSArray *contentVCClassArray; // 內容控制器類名數(shù)組
懶加載:
#pragma mark - Getters And Setters
- (UIScrollView *)titleScrollView {
if (!_titleScrollView) {
_titleScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 64, SCREENWIDTH, 44)];
_titleScrollView.contentSize = CGSizeMake(titleLabelWidth * self.contentVCClassArray.count, 0);
// 隱藏水平滾動條
_titleScrollView.showsHorizontalScrollIndicator = NO;
}
return _titleScrollView;
}
- (UIScrollView *)contentScrollView {
if (!_contentScrollView) {
_contentScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(self.titleScrollView.frame), SCREENWIDTH, SCREENHEIGHT - 44)];
_contentScrollView.contentSize = CGSizeMake(SCREENWIDTH * self.contentVCClassArray.count, 0);
// 開啟分頁
_contentScrollView.pagingEnabled = YES;
// 關閉回彈
_contentScrollView.bounces = NO;
// 隱藏水平滾動條
_contentScrollView.showsHorizontalScrollIndicator = NO;
// 設置代理
_contentScrollView.delegate = self;
}
return _contentScrollView;
}
- (NSArray *)titleArray {
if (!_titleArray) {
_titleArray = @[@"紅", @"藍", @"綠", @"黃", @"紫", @"橘"];
}
return _titleArray;
}
- (NSArray *)contentVCClassArray {
if (!_contentVCClassArray) {
_contentVCClassArray = @[@"DBHRedViewController",
@"DBHBlueViewController",
@"DBHGreenViewController",
@"DBHYellowViewController",
@"DBHPurPleViewController",
@"DBHOrangeViewController"];
}
return _contentVCClassArray;
}
方法介紹:
#pragma mark - Private Methods
/**
添加所有子控制器對應的標題
*/
- (void)addTitleLabels {
for (NSInteger i = 0; i < self.contentVCClassArray.count; i++) {
UILabel *titleLabel = [[UILabel alloc] init];
titleLabel.tag = 200 + i;
titleLabel.frame = CGRectMake(titleLabelWidth * i, 0, titleLabelWidth, 44);
titleLabel.text = self.titleArray[i];
titleLabel.textAlignment = NSTextAlignmentCenter;
titleLabel.highlightedTextColor = [UIColor redColor];
titleLabel.userInteractionEnabled = YES;
UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(respondsToTitleLabel:)];
[titleLabel addGestureRecognizer:tapGR];
// 默認選中第1個titleLabel
if (!i) {
[self respondsToTitleLabel:tapGR];
}
[self.titleScrollView addSubview:titleLabel];
}
}
/**
添加所有子控制器
*/
- (void)addChildViewControllers {
for (NSInteger i = 0; i < self.contentVCClassArray.count; i++) {
NSString *contentVCClassName = self.contentVCClassArray[i];
UIViewController *contentVC = [[NSClassFromString(contentVCClassName) alloc] init];
[self addChildViewController:contentVC];
contentVC.view.frame = CGRectMake(SCREENWIDTH * i, 0, SCREENWIDTH, SCREENHEIGHT);
[self.contentScrollView addSubview:contentVC.view];
}
}
/**
選中l(wèi)abel
*/
- (void)selectedLabel:(UILabel *)label {
// 還原前一個選中l(wèi)abel的屬性
self.currentSelectedTitleLabel.highlighted = NO;
self.currentSelectedTitleLabel.transform = CGAffineTransformIdentity;
self.currentSelectedTitleLabel.textColor = [UIColor blackColor];
// 修改選中l(wèi)abel的屬性
label.highlighted = YES;
label.transform = CGAffineTransformMakeScale(scale, scale);
// 更改選中的label
self.currentSelectedTitleLabel = label;
// 居中選中的label
CGFloat offsetX = label.center.x - SCREENWIDTH * 0.5;
CGFloat maxOffsetX = self.titleScrollView.contentSize.width - SCREENWIDTH;
if (offsetX < 0) {
offsetX = 0;
} else if (offsetX > maxOffsetX) {
offsetX = maxOffsetX;
}
[self.titleScrollView setContentOffset:CGPointMake(offsetX, 0) animated:YES];
}
/**
顯示選中標題對面的控制器view
@param index 選中標題的下標
*/
- (void)showContentVC:(NSInteger)index {
// 移動內容scrollView到指定位置
self.contentScrollView.contentOffset = CGPointMake(SCREENWIDTH * index, 0);
}
代碼到這里就完畢了晦雨,具體使用可以參考源碼demo,這里所有的子控制器一開始就成為了當前主控制器的子控制器隘冲。因為我這里的標簽數(shù)量比較少闹瞧,所以所有子控制器的視圖當成為子控制器的時候就已經(jīng)添加到內容UIScrollView上面了,當標簽數(shù)量比較多時展辞,可以在一開始的時候只添加為子控制器奥邮,無須將子控制器的視圖加載到內容UIScrollview上,當需要顯示的時候再加上去以節(jié)省內存,不過這樣的話洽腺,當?shù)谝淮渭虞d視圖的時候會有一個明顯的空白區(qū)域脚粟,看著不大舒服。
Demo地址