iOS-UIScrollview滑動時標題欄自動隱藏和顯示效果
本文主要介紹如何實現當UIScrollview滑動時,自動隱藏和顯示標題欄的效果。其中佈局採用Autolayout的方式,並且為了程式碼精簡,使用了第三方庫Masonry,其使用參考【iOS-Masonry學習筆記】。使用它的原因是可以很好的結合動畫效果的實現!
一、佈局
首先我們來介紹一下整個佈局。最外層的是一個UIScrollview(mainScrollview),其子檢視包括一個模擬標題欄的UIView檢視,以及一個UIScrollview檢視(innerScrollview),並且其是按順序上下排列的。其中的innerScrollview包含一個UIView容器子檢視,並且該容器中包括若干個UIView子檢視來模擬cell。其顯示效果大致如下:
1.1 常量設定
//螢幕寬度
#define UIScreenWidth [[UIScreen mainScreen] bounds].size.width
//螢幕高度
#define UIScreenHeight [[UIScreen mainScreen] bounds].size.height
//標題欄高度
NSInteger const titleHeight = 100;
//每個cell高度
NSInteger const cellHeight = 80;
//觸發標題欄隱藏和顯示事件的scrollview在Y方向上的滑動位移閾值
NSInteger const triggerToHideY = 200;
1.2 檢視初始化
整個佈局的檢視屬性並不多,主要是一下這些。其中cells陣列用於儲存新增到container中的子UIView檢視,以便於此後的檢視約束設定。還有一個屬性isHide是用來表示標題的狀態的,如果標題隱藏則為YES,反之為NO,預設值為NO;
@property (strong, nonatomic) UIScrollView *mainScrollview;
@property (strong, nonatomic) UIView *hideView;
@property (strong, nonatomic) UIScrollView *innerScrollview;
@property (strong, nonatomic) UIView *container;
@property (strong, nonatomic) NSMutableArray *cells;
@property (nonatomic) BOOL isHide;
接下來則是手動初始化各個檢視物件,並設定它們的父子關係。
- (void)viewDidLoad {
[super viewDidLoad];
//設定預設值
self.isHide = NO;
//初始化cells陣列
self.cells = [NSMutableArray new];
//初始化mainScrollview檢視
self.mainScrollview = [UIScrollView new];
[self.mainScrollview setBackgroundColor:[UIColor whiteColor]];
[self.view addSubview:self.mainScrollview];
//初始化hideView檢視
self.hideView = [UIView new];
[self.hideView setBackgroundColor:[UIColor colorWithRed:0.000 green:0.502 blue:1.000 alpha:1.000]];
[self.mainScrollview addSubview:self.hideView];
//初始化container
self.container = [UIView new];
[self.container setBackgroundColor:[UIColor whiteColor]];
//初始化innerScrollView,預設開啟彈簧效果
self.innerScrollview = [UIScrollView new];
self.innerScrollview.delegate = self;
//self.innerScrollview.bounces = NO;
[self.innerScrollview setBackgroundColor:[UIColor blackColor]];
[self.innerScrollview addSubview:self.container];
[self.mainScrollview addSubview:self.innerScrollview];
//生成若干個子檢視,並新增到container中
for (int i = 0; i < 20; i++) {
UIView *view = [[UIView alloc] init];
[view setBackgroundColor:[UIColor colorWithRed:1-(i*10.0/255) green:1-(i*10.0/255) blue:1-(i*10.0/255) alpha:1.0f]];
[self.container addSubview:view];
[self.cells addObject:view];
}
}
1.3 檢視約束
檢視的約束主要是採用Autolayout的佈局思路,並使用第三方框架Masonry。哈哈大家可以看到使用框架之後省了好多程式碼量哈哈哈。
-(void)updateViewConstraints
{
//設定mainScrollview約束
[self.mainScrollview mas_makeConstraints:^(MASConstraintMaker *make) {
//其邊距與sel.view相等,即全屏顯示
make.edges.equalTo(self.view);
}];
//設定hideView約束
[self.hideView mas_makeConstraints:^(MASConstraintMaker *make) {
//其上,左,右邊距緊靠mainScrollview
make.top.left.right.equalTo(self.mainScrollview);
//X方向上居中
make.centerX.equalTo(self.mainScrollview);
//設定標題的高度
make.height.equalTo(@(titleHeight));
}];
//設定innerScrollview約束
[self.innerScrollview mas_makeConstraints:^(MASConstraintMaker *make) {
//其top緊靠標題的bottom,即它位於標題下方
make.top.equalTo(self.hideView.mas_bottom);
//左,右,下緊靠mainScrollview
make.left.and.right.equalTo(self.mainScrollview);
make.centerY.equalTo(self.mainScrollview).with.centerOffset(CGPointMake(0, titleHeight));
}];
//設定container約束
[self.container mas_makeConstraints:^(MASConstraintMaker *make) {
//containt主要約束為和innerScrollview的大小一致
make.edges.equalTo(self.innerScrollview);
make.width.equalTo(self.innerScrollview);
}];
//設定每個cell的約束
for (int i = 0; i < self.cells.count; i++) {
//獲取需要約束的檢視
UIView *subview = self.cells[i];
[subview mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.left.centerX.equalTo(self.container);
make.height.equalTo(@(cellHeight));
//如果是第一個cell,則其top屬性緊靠container容器
//否則每個cell的top屬性緊靠上一個cell的bottom屬性
if (i == 0) {
make.top.equalTo(self.container);
}
else{
UIView *topView = self.cells[i - 1];
make.top.equalTo(topView.mas_bottom);
}
}];
}
//設定容器底部約束
[self.container mas_makeConstraints:^(MASConstraintMaker *make) {
//約束容器的bottom緊靠最後一個cell的bottom
//完成這個約束InnerScrollview就可以自動計算contentSize
//然後就可以滑動了!很神奇是不是!
UIView *lastView = self.cells[self.cells.count - 1];
make.bottom.equalTo(lastView.mas_bottom);
}];
//最後不要忘了呼叫超類的方法
[super updateViewConstraints];
}
二、自動隱藏和顯示
接下來就是如何實現自動隱藏和顯示了。其實這個也很簡單,瞭解UIScrollview的就會知道其有一個協議為UIScrollViewDelegate
,其中包括了一些當scrollview滑動時會回撥的函式,滑動動畫開始、結束時的回撥,使用者手指拖拽和結束拖拽等諸多事件的回撥。在這裡我們主要用到的回撥方法為scrollViewDidScroll:
,就是當scrollview出現滑動事件時就會回撥的方法。
所以首先要實現該協議。
@interface ViewController () <UIScrollViewDelegate>
然後設定innerScrollview的delegate屬性。
self.innerScrollview.delegate = self;
最後則是實現scrollViewDidScroll:
方法。在方法裡,先判斷scrollview滑動的距離是否達到了觸發自動隱藏和顯示的閾值,然後判斷當前標題欄的狀態再是否需要進行動畫隱藏和顯示。其中動畫實現的原理很簡單,當需要隱藏標題欄時,則將標題檢視移出檢視(可以考慮將其也隱藏),並且重新設定InnerScrollview的顯示區域。(更多UIScrollView相關參考【iOS實戰-自定義的橫向滾動控制元件CustomScrollView】)
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (scrollView.contentOffset.y > triggerToHideY) {
if (!self.isHide) {
self.isHide = YES;
[UIView animateWithDuration:0.3 animations:^{
self.hideView.center = CGPointMake(self.hideView.center.x, -self.hideView.center.y);
self.innerScrollview.frame = CGRectMake(0, 0, UIScreenWidth, UIScreenHeight);
}];
}
}
else if(scrollView.contentOffset.y < triggerToHideY){
if (self.isHide) {
self.isHide = NO;
[UIView animateWithDuration:0.3 animations:^{
self.hideView.center = CGPointMake(self.hideView.center.x, -(self.hideView.center.y));
self.innerScrollview.frame = CGRectMake(0, titleHeight, UIScreenWidth, UIScreenHeight);
}];
}
}
}
2.1 效果圖
這就是大概的效果圖,對於動畫的一些設定可以調整一下(動畫時間啊,動畫時間函式什麼的),可能會有更好的效果。
三、原始碼
工程的原始碼已經上傳到了Github上。由於本專案是使用了cocoapods進行第三方框架的引入,所以如果有問題的話可以考慮pod install
或pod update
一下。如果還有別的問題可以聯絡我。