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 效果图

这就是大概的效果图,对于动画的一些设置可以调整一下(动画时间啊,动画时间函数什么的),可能会有更好的效果。

iOS-UIScrollview滑动时标题栏自动隐藏和显示效果_第1张图片

三、源代码

  工程的源代码已经上传到了Github上。由于本项目是使用了cocoapods进行第三方框架的引入,所以如果有问题的话可以考虑pod installpod update一下。如果还有别的问题可以联系我。

  项目为iOSDemon中的iOS_UI_study目录下的UIScrollviewAndHideView工程。
【传送门-iOSDemon-iOS_UI_study-UIScrollviewAndHideView】

你可能感兴趣的:(动画,布局,uiscrollview)