文档章节

UICollectionView带头视图和组的头视图同时存在且组视图可悬停在顶部的实现

 半世微凉
发布于 2017/07/12 16:55
字数 1261
阅读 106
收藏 0
点赞 0
评论 0

让对象collectionView有头视图,很简单看代码,具体细节当然自己去定制了。

self.collectionView.contentInset = UIEdgeInsetsMake(150, 0, 0, 0);
// 注意这里设置headerView的头视图的y坐标一定是从"负值"开始,因为headerView是添加在collectionView上的.
UIView *headerView = [[UIView alloc]initWithFrame:CGRectMake(0, -150, self.view.frame.size.width, 150)];
[self.collectionView addSubview:headerView];

执行上面操作后你就有了150像素的头视图了。头部视图OK,接下来组的头视图。不废话上代码。

#import <UIKit/UIKit.h>

@interface StoreCollectionViewFlowLayout : UICollectionViewFlowLayout
@property (nonatomic, assign) CGFloat navHeight;
@end

#import "StoreCollectionViewFlowLayout.h"

@implementation StoreCollectionViewFlowLayout
- (instancetype)init
{
    self = [super init];
    if (self)
    {
        self.navHeight = 0;
    }
    return self;
}

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    //UICollectionViewLayoutAttributes:我称它为collectionView中的item(包括cell和header、footer这些)的《结构信息》
    //截取到父类所返回的数组(里面放的是当前屏幕所能展示的item的结构信息),并转化成不可变数组
    NSMutableArray *superArray = [[super layoutAttributesForElementsInRect:rect] mutableCopy];
    
    //创建存索引的数组,无符号(正整数),无序(不能通过下标取值),不可重复(重复的话会自动过滤)
    NSMutableIndexSet *noneHeaderSections = [NSMutableIndexSet indexSet];
    //遍历superArray,得到一个当前屏幕中所有的section数组
    for (UICollectionViewLayoutAttributes *attributes in superArray)
    {
        //如果当前的元素分类是一个cell,将cell所在的分区section加入数组,重复的话会自动过滤
        if (attributes.representedElementCategory == UICollectionElementCategoryCell)
        {
            [noneHeaderSections addIndex:attributes.indexPath.section];
        }
    }
    
    //遍历superArray,将当前屏幕中拥有的header的section从数组中移除,得到一个当前屏幕中没有header的section数组
    //正常情况下,随着手指往上移,header脱离屏幕会被系统回收而cell尚在,也会触发该方法
    for (UICollectionViewLayoutAttributes *attributes in superArray)
    {
        //如果当前的元素是一个header,将header所在的section从数组中移除
        if ([attributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader])
        {
            [noneHeaderSections removeIndex:attributes.indexPath.section];
        }
    }
    
    //遍历当前屏幕中没有header的section数组
    [noneHeaderSections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop){
        
        //取到当前section中第一个item的indexPath
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:idx];
        //获取当前section在正常情况下已经离开屏幕的header结构信息
        UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:indexPath];
        
        //如果当前分区确实有因为离开屏幕而被系统回收的header
        if (attributes)
        {
            //将该header结构信息重新加入到superArray中去
            [superArray addObject:attributes];
        }
    }];
    
    //遍历superArray,改变header结构信息中的参数,使它可以在当前section还没完全离开屏幕的时候一直显示
    for (UICollectionViewLayoutAttributes *attributes in superArray) {
        
        //如果当前item是header
        if ([attributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader])
        {
            //得到当前header所在分区的cell的数量
            NSInteger numberOfItemsInSection = [self.collectionView numberOfItemsInSection:attributes.indexPath.section];
            //得到第一个item的indexPath
            NSIndexPath *firstItemIndexPath = [NSIndexPath indexPathForItem:0 inSection:attributes.indexPath.section];
            //得到最后一个item的indexPath
            NSIndexPath *lastItemIndexPath = [NSIndexPath indexPathForItem:MAX(0, numberOfItemsInSection-1) inSection:attributes.indexPath.section];
            //得到第一个item和最后一个item的结构信息
            UICollectionViewLayoutAttributes *firstItemAttributes, *lastItemAttributes;
            if (numberOfItemsInSection>0)
            {
                //cell有值,则获取第一个cell和最后一个cell的结构信息
                firstItemAttributes = [self layoutAttributesForItemAtIndexPath:firstItemIndexPath];
                lastItemAttributes = [self layoutAttributesForItemAtIndexPath:lastItemIndexPath];
            }else
            {
                //cell没值,就新建一个UICollectionViewLayoutAttributes
                firstItemAttributes = [UICollectionViewLayoutAttributes new];
                //然后模拟出在当前分区中的唯一一个cell,cell在header的下面,高度为0,还与header隔着可能存在的sectionInset的top
                CGFloat y = CGRectGetMaxY(attributes.frame)+self.sectionInset.top;
                firstItemAttributes.frame = CGRectMake(0, y, 0, 0);
                //因为只有一个cell,所以最后一个cell等于第一个cell
                lastItemAttributes = firstItemAttributes;
            }
            
            //获取当前header的frame
            CGRect rect = attributes.frame;
            
            //当前的滑动距离 + 因为导航栏产生的偏移量,默认为64(如果app需求不同,需自己设置)
            CGFloat offset = self.collectionView.contentOffset.y + self.navHeight;
            
            //第一个cell的y值 - 当前header的高度 - 可能存在的sectionInset的top
            CGFloat headerY = firstItemAttributes.frame.origin.y - rect.size.height - self.sectionInset.top;
            
            //哪个大取哪个,保证header悬停
            //针对当前header基本上都是offset更加大,针对下一个header则会是headerY大,各自处理
            CGFloat maxY = MAX(offset,headerY);
            
            //最后一个cell的y值 + 最后一个cell的高度 + 可能存在的sectionInset的bottom - 当前header的高度
            //当当前section的footer或者下一个section的header接触到当前header的底部,计算出的headerMissingY即为有效值
            CGFloat headerMissingY = CGRectGetMaxY(lastItemAttributes.frame) + self.sectionInset.bottom - rect.size.height;
            
            //给rect的y赋新值,因为在最后消失的临界点要跟谁消失,所以取小
            rect.origin.y = MIN(maxY,headerMissingY);
            //给header的结构信息的frame重新赋值
            attributes.frame = rect;
            
            //如果按照正常情况下,header离开屏幕被系统回收,而header的层次关系又与cell相等,如果不去理会,会出现cell在header上面的情况
            //通过打印可以知道cell的层次关系zIndex数值为0,我们可以将header的zIndex设置成1,如果不放心,也可以将它设置成非常大,这里随便填了个7
            attributes.zIndex = 7;
        }
    }
    
    //转换回不可变数组,并返回
    return [superArray copy];
    
}

//return YES;表示一旦滑动就实时调用上面这个layoutAttributesForElementsInRect:方法
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBound
{
    return YES;
}
@end

navHeight 看自己需要设置就好了。

创建一个UICollectionViewFlowLayout的对象时候就用上面这个类,collectionView的其他设置就不多写了!至此一切OK!

解决MJRefresh刷新控件不见的问题,发现刷新控件不见了!

    _collectionView.mj_header.ignoredScrollViewContentInsetTop = 150;

 

© 著作权归作者所有

共有 人打赏支持
粉丝 0
博文 1
码字总数 1261
作品 0
常德
「iOS」高仿【少数派】客户端 代码+思路讲解

少数派 一、写在前面 在我的iOS开发学习过程中,阅读过许多同学的高仿项目文章、源码,对我助益颇深。但是许许多多的高仿项目在技术方面各有侧重,所以我先把本项目中值得探讨的技术点列出,...

halohily
2017/09/13
0
0
「iOS」高仿【少数派】客户端 代码+思路讲解

少数派 一、写在前面 在我的iOS开发学习过程中,阅读过许多同学的高仿项目文章、源码,对我助益颇深。但是许许多多的高仿项目在技术方面各有侧重,所以我先把本项目中值得探讨的技术点列出,...

halohily
2017/11/26
0
0
怎样在UICollectionView中添加Header和footer

在前面我们已经学过,每个collection view都必须有数据源为其提供内容。它的责任是为collection views完成以下的事情: 控制collection view的section数目 每个section中的item的个数 为特定...

人生天地间
2014/04/12
0
7
UICollectionViewController的使用

分享一下collectionviewcontroller的用法,不足之处请大家补充 1.init生成controller时需要生成相应的layout,否则报错 (instancetype)init { //创建一个流式布局对象 UICollectionViewFlow...

鄙人浪淘沙
2016/08/29
1K
0
iOS流布局UICollectionView系列三——使用FlowLayout进行更灵活布局

iOS流布局UICollectionView系列三——使用FlowLayout进行更灵活布局 一、引言 前面的博客介绍了UICollectionView的相关方法和其协议中的方法,但对布局的管理类UICollectionViewFlowLayout没...

珲少
2015/10/27
0
2
DevExpress v17.2新版亮点——VCL篇(二)

用户界面套包DevExpress v17.2日前终于正式发布,本站将以连载的形式为大家介绍各版本新增内容。本文将介绍了DevExpress VCL v17.2 的新功能,快来下载试用新版本!点击下载>> DPI Awarenes...

Miss_Hello_World
05/30
0
0
iOS开发中的小技巧

01 - UITableView的Group样式下顶部空白处理 02 - UITableView的plain样式下,取消区头停滞效果 那个,其实,还是用Group样式吧哈哈。 03 - 获取某个view所在的控制器 04 - 两种方法删除NSU...

我是IT码农
2016/11/03
10
2
在Collection View中处理单个或多个选择

在前面我们已经学过了UICollectionView的基本的东西。如果你没有看过你可以去看看前面的写的文章。 正如前面提到的那样,Collection view和UITableView很相似,但我们将给你一个更好的方法去...

人生天地间
2014/04/14
0
0
PDKTStickySectionHeadersCollectionView

PDKTStickySectionHeadersCollectionViewLayout 是个 UICollectionView 布局,使部分标题放在集合视图的顶部。

叶秀兰
2014/02/08
137
0
iOS小技巧总结,绝对有你想要的

字数947 阅读2032 评论26 喜欢99 在这里总结一些iOS开发中的小技巧,能大大方便我们的开发,持续更新。 UITableView的Group样式下顶部空白处理 UITableView的plain样式下,取消区头停滞效果 ...

andyhe91
2016/09/07
76
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

SpringBoot | 第十章:Swagger2的集成和使用

前言 前一章节介绍了mybatisPlus的集成和简单使用,本章节开始接着上一章节的用户表,进行Swagger2的集成。现在都奉行前后端分离开发和微服务大行其道,分微服务及前后端分离后,前后端开发的...

oKong
今天
5
0
Python 最小二乘法 拟合 二次曲线

Python 二次拟合 随机生成数据,并且加上噪声干扰 构造需要拟合的函数形式,使用最小二乘法进行拟合 输出拟合后的参数 将拟合后的函数与原始数据绘图后进行对比 import numpy as npimport...

阿豪boy
今天
1
0
云拿 无人便利店

附近(上海市-航南路)开了家无人便利店.特意进去体验了一下.下面把自己看到的跟大家分享下. 经得现场工作人员同意后拍了几张照片.从外面看是这样.店门口的指导里强调:不要一次扫码多个人进入....

周翔
昨天
1
0
Java设计模式学习之工厂模式

在Java(或者叫做面向对象语言)的世界中,工厂模式被广泛应用于项目中,也许你并没有听说过,不过也许你已经在使用了。 简单来说,工厂模式的出现源于增加程序序的可扩展性,降低耦合度。之...

路小磊
昨天
165
1
npm profile 新功能介绍

转载地址 npm profile 新功能介绍 npm新版本新推来一个功能,npm profile,这个可以更改自己简介信息的命令,以后可以不用去登录网站来修改自己的简介了 具体的这个功能的支持大概是在6这个版...

durban
昨天
1
0
Serial2Ethernet Bi-redirection

Serial Tool Serial Tool is a utility for developing serial communications, custom protocols or device testing. You can set up bytes to send accordingly to your protocol and save......

zungyiu
昨天
1
0
python里求解物理学上的双弹簧质能系统

物理的模型如下: 在这个系统里有两个物体,它们的质量分别是m1和m2,被两个弹簧连接在一起,伸缩系统为k1和k2,左端固定。假定没有外力时,两个弹簧的长度为L1和L2。 由于两物体有重力,那么...

wangxuwei
昨天
0
0
apolloxlua 介绍

##项目介绍 apolloxlua 目前支持javascript到lua的翻译。可以在openresty和luajit里使用。这个工具分为两种模式, 一种是web模式,可以通过网页使用。另外一种是tool模式, 通常作为大规模翻...

钟元OSS
昨天
2
0
Mybatis入门

简介: 定义:Mybatis是一个支持普通SQL查询、存储过程和高级映射的持久层框架。 途径:MyBatis通过XML文件或者注解的形式配置映射,实现数据库查询。 特性:动态SQL语句。 文件结构:Mybat...

霍淇滨
昨天
2
0
开发技术瓶颈期,如何突破

前言 读书、学习的那些事情,以前我也陆续叨叨了不少,但总觉得 “学习方法” 就是一个永远在路上的话题。个人的能力、经验积累与习惯方法不尽相同,而且一篇文章甚至一本书都很难将学习方法...

_小迷糊
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部