美文网首页我依然爱iOS
iOS实例——滑动列表展现/隐藏顶部视图

iOS实例——滑动列表展现/隐藏顶部视图

作者: Cloudox_ | 来源:发表于2017-11-27 10:42 被阅读87次

    项目中需要一个效果:下滚列表时顶部的自定义视图不移动,上移时隐藏顶部视图,提高列表的展现范围。在此基础上海加了一个隐藏列表时的动态渐入渐出效果,如下:

    20170420170947324.gif

    实现

    实现的要点是,顶部的视图要随着列表的滚动而滚动,且列表最上是可以滚动到屏幕顶部的,最下就是滚动到一个固定的位置就不再往下滚动了,至于渐变效果只要能控制滚动自然也能控制随着滚动去改变alpha值了。

    关键就在于顶部视图不是简单的放在列表之上,也不是简单的作为列表的headerview。

    顶部视图确实是直接作为self.view的子视图来添加的,但是列表的范围同样是覆盖整个屏幕,那么为了避免列表内容被顶部视图盖住,就要设置列表的contentoffset值。

    要注意的是,设置contentoffset值必须在添加列表到self.view之后,否则无效,设置之后可能你会发现刚开始是好的,一点击列表内容就回到顶部了,别慌,那是之后会解决的问题:

        self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, SCREENWIDTH, SCREENHEIGHT)];
        self.tableView.delegate = self;
        self.tableView.dataSource = self;
        self.tableView.tableFooterView = [[UIView alloc] init];// 去除多余的列表线条
        [self.view addSubview:self.tableView];
        [self.tableView setContentOffset:CGPointMake(0, -200)];
    

    我们的顶部视图要跟随列表滚动,就必须获知列表的滚动效果,这里我们在自定义的顶部视图类中加一个UIScrollView属性,在初始化的时候就将我们的列表赋给这个属性(UITableView是UIScrollView的子类):

        OXScrollHeaderView *scrollHeader = [[OXScrollHeaderView alloc] initWithFrame:CGRectMake(0, 0, SCREENWIDTH, 200)];
        scrollHeader.headerScrollView = self.tableView;
        [self.view addSubview:scrollHeader];
    

    可以看到顶部视图是直接添加到self.view上的。

    视图的内容可以自己定义,我就只放了一张图片。

    对于滚动的跟随,我们采用KVO键值观察(可以查看这篇博客来了解)来做。这里我们利用UIView的一个Delegate:willMoveToSuperview:,它会在我们的视图被添加到父视图上时被调用,在这个代理方法中我们就添加对列表的contentoffset值的观察,每次这个值变化时就调用处理方法:

    #pragma mark - UIView Delegate
    // 在被添加到界面上时就添加对contentoffset的观察
    - (void)willMoveToSuperview:(UIView *)newSuperview {
        [self.headerScrollView addObserver:self forKeyPath:@"contentOffset" options:(NSKeyValueObservingOptionNew) context:Nil];
        self.headerScrollView.contentInset = UIEdgeInsetsMake(BOTTOM, 0, 0, 0);
    }
    
    #pragma mark - KVO
    // 对contentoffset的键值观察
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
        CGPoint newOffset = [change[@"new"] CGPointValue];
        
    //    NSLog(@"%f, %f", newOffset.x, newOffset.y);
        
        [self updateSubViewsWithScrollOffset:newOffset];
    }
    

    这里我们设置了一下contentInset,它是是scrollview的contentview的顶点相对于scrollview的位置,四个参数分别代表距离上,左,下,右边的像素长度。这样就不会一点列表就移动到被遮挡了。

    在处理方法中我们要做两件事,第一件事是让顶部视图的高度随着列表移动而移动,但是要控制列表最高移动到的位置TOP和最低移动到的位置BOTTOM,这其实就是顶部视图的低端对应的Y值。

    第二件事是让顶部视图随着移动而渐变,当移动到最高时彻底透明,移动到最低时不透明,这个alpha值也是根据移动的值来计算的:

    - (void)updateSubViewsWithScrollOffset:(CGPoint)newOffset {
        
    //    NSLog(@"scrollview inset top:%f", self.headerScrollView.contentInset.top);
    //    NSLog(@"new offset before:%f", newOffset.y);
    //    NSLog(@"newOffset : %f", newOffset.y);
        
        float startChangeOffset = - self.headerScrollView.contentInset.top;// -BOTTOM
        
        // 往下拉的时候是否超过BOTTOM,超过的话保持BOTTOM不变,往上滑的话是否低于TOP,是的话保持TOP,也就是最多滑到BOTTOM,最少有TOP
        newOffset = CGPointMake(newOffset.x, newOffset.y < startChangeOffset ? startChangeOffset : (newOffset.y > -TOP ? -TOP : newOffset.y));
    //    NSLog(@"new offset after:%f", newOffset.y);
        
        // 头部视图的y坐标
        float newY = - newOffset.y - BOTTOM;//self.headerScrollView.contentInset.top;
        // 随着滑动将头部视图往上同步移动
        self.frame = CGRectMake(0, newY, self.frame.size.width, self.frame.size.height);
        
        // 算alpha,保证在滑到BOTTOM时为1,TOP时为0
        float d = -TOP - startChangeOffset;
        float alpha = 1 - (newOffset.y - startChangeOffset) / d;
        
        self.alpha = alpha;
        
        
    //    NSLog(@"current offset: %f", newOffset.y);
        
    }
    

    这里我的工程中顶部视图高度为200,所以TOP设为0,BOTTOM设为200。

    示例工程

    可以直接下载示例工程进行详细的了解和需要的修改:https://github.com/Cloudox/ScrollShowHeaderDemo


    查看作者首页

    相关文章

      网友评论

        本文标题:iOS实例——滑动列表展现/隐藏顶部视图

        本文链接:https://www.haomeiwen.com/subject/ysprbxtx.html