功能介紹
最近在做一款ios的app砰蠢,其中有一個頁面需要分成三個版塊,版塊之間可以通過左右滑動來進行切換,也可以通過點擊上方的按鈕來切換,好像在android中可以用過ViewPager + Fragment來實現(xiàn)罚屋。界面大概就是這個樣子,這里我以知乎客戶端的發(fā)現(xiàn)頁面為例:
其中整個頁面分為三個小的版塊蕊苗,分別"推薦"沿后,"熱門"以及"收藏"沿彭。點擊上方的文字后朽砰,下方的頁面會切換到對應(yīng)的版塊,同時文字下方的藍色導(dǎo)航條也會隨著界面的切換跟著滑動喉刘。另外瞧柔,當(dāng)我們不通過按鈕切換,用手勢在頁面上左右滑動時睦裳,導(dǎo)航條也會跟著一起滑動造锅。功能大概就是這個樣子。
原理
下面簡單分析下實現(xiàn)原理廉邑。首先在"發(fā)現(xiàn)"的下方應(yīng)該有UIView哥蔚,在UIView中放有3個UIButton。至于文字下方的導(dǎo)航條蛛蒙,可以用UILabel來做糙箍,寬度等于一個按鈕的寬度,并將背景色改為藍色牵祟。導(dǎo)航條下方的頁面可以通過手勢來左右滑動深夯,首先想到的應(yīng)該就是,這是一個UIScrollView诺苹,我們需要將scrollView的contentSize屬性設(shè)置成三個頁面寬度的大小咕晋,否則會無法滑動頁面。然后在scrollView放上三個版塊的頁面收奔,這個根據(jù)自身的業(yè)務(wù)情況而定掌呜,一般UITableView用得比較多。最后坪哄,怎樣才能讓頁面滑動的時候?qū)Ш綏l也跟著移動的质蕉?在Android中呢撞,一般的做法就是給scrollView中添加一個事件監(jiān)聽器,用來監(jiān)聽滑動事件饰剥,并在事件處理函數(shù)中執(zhí)行響應(yīng)的邏輯殊霞。在ios中沒有事件監(jiān)聽這個概念,我們可以為scrollView設(shè)置它的代理汰蓉,并在代理類中覆蓋掉該方法:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
設(shè)置了代理類后绷蹲,代理類其實就是幫我們注冊了相應(yīng)的回調(diào)函數(shù),每次scrollView只要有細微的滑動顾孽,該方法就會被調(diào)用祝钢。在方法中,需要做的就是獲取scrollView當(dāng)前的偏移量若厚,然后根據(jù)這個偏移量來設(shè)定導(dǎo)航條的位置拦英。
代碼實現(xiàn)
將scrollView與滾動條聲明未全局變量,因為在其他方法中也會用到测秸。
//存放三個按鈕的父頁面寬度
#define TOP_VIEW_HEIGHT 50
//界面上方導(dǎo)航線條的寬度
#define NAVIGATION_LINE_HEIGHT 2
@interface MyMesgViewController () <UIScrollViewDelegate>
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UILabel *navLabel;
@end
scrollView延遲初始化疤估,在初始化時記得為其設(shè)置代理對象。
- (UIScrollView *)scrollView {
if (!_scrollView) {
CGFloat scrollViewHeight = 64 + TOP_VIEW_HEIGHT + 8;
_scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, scrollViewHeight, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - scrollViewHeight)];
_scrollView.showsHorizontalScrollIndicator = NO;
_scrollView.pagingEnabled = YES;
CGSize size = _scrollView.frame.size;
size.width *= 3;
_scrollView.contentSize = size;
_scrollView.backgroundColor = [UIColor whiteColor];
_scrollView.delegate = self;
[self.view addSubview:_scrollView];
}
return _scrollView;
}
navLabel延遲初始化
- (UILabel *)navLabel {
if (!_navLabel) {
_navLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, TOP_VIEW_HEIGHT - NAVIGATION_LINE_HEIGHT, [UIScreen mainScreen].bounds.size.width / 3, NAVIGATION_LINE_HEIGHT)];
_navLabel.backgroundColor = [UIColor blueColor];
}
return _navLabel;
}
將三個按鈕添加到頁面中霎冯,并為按鈕添加點擊事件處理函數(shù)铃拇。
- (void)addMessageCategoryButton {
UIView *topView = [[UIView alloc] initWithFrame:CGRectMake(0, 64, [UIScreen mainScreen].bounds.size.width, TOP_VIEW_HEIGHT)];
topView.backgroundColor = [UIColor whiteColor];
UIButton *approvedMsgButton = [self createMsgButton:@"審核消息" posX:0];
UIButton *mosMsgButton = [self createMsgButton:@"M幣交易" posX:approvedMsgButton.frame.size.width];
UIButton *systemMsgButton = [self createMsgButton:@"系統(tǒng)通知" posX:approvedMsgButton.frame.size.width * 2];
[topView addSubview:approvedMsgButton];
[topView addSubview:mosMsgButton];
[topView addSubview:systemMsgButton];
[topView addSubview:self.navLabel];
[self.view addSubview:topView];
}
將創(chuàng)建按鈕的過程單獨抽象出來
- (UIButton *)createMsgButton:(NSString *)title posX:(CGFloat)posX {
UIButton *msgButton = [[UIButton alloc] initWithFrame:CGRectMake(posX, 0, self.view.frame.size.width / 3, TOP_VIEW_HEIGHT - NAVIGATION_LINE_HEIGHT)];
msgButton.backgroundColor = [UIColor whiteColor];
NSAttributedString *attributeTitle = [[NSAttributedString alloc] initWithString:title attributes:@{ NSFontAttributeName : [UIFont systemFontOfSize:14] }];
[msgButton setAttributedTitle:attributeTitle forState:UIControlStateNormal];
msgButton.tag = (NSInteger) (posX / (self.view.frame.size.width / 3));
[msgButton addTarget:self action:@selector(switchMessageDetailView:) forControlEvents:UIControlEventTouchUpInside];
return msgButton;
}
按鈕點擊后調(diào)用的函數(shù),即切換頁面
- (void)switchMessageDetailView:(UIButton *)btn {
[self.scrollView setContentOffset:CGPointMake(btn.tag * self.view.frame.size.width, 0) animated:YES];
}
最后沈撞,在回調(diào)函數(shù)中根據(jù)scrollView的偏移量調(diào)整導(dǎo)航條的位置慷荔。
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint offset = scrollView.contentOffset;
CGFloat x = offset.x / 3;
if (x > 0 && x < scrollView.frame.size.width) {
CGRect frame = self.navLabel.frame;
frame.origin.x = x;
self.navLabel.frame = frame;
}
}
這是最終的效果圖: