1. 程式人生 > >iOS-UIScrollview滑動時標題欄自動隱藏和顯示效果

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 installpod update一下。如果還有別的問題可以聯絡我。