博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
UICollectionView间隙的坑
阅读量:6485 次
发布时间:2019-06-23

本文共 5715 字,大约阅读时间需要 19 分钟。

前言

笔者之前用UICollectionView实现了一个课程表。

分为两个部分,左边节数1~6为section 0,右边课程为section1,采用垂直布局。

但换了个屏幕就凉凉了,section0排版出了问题。

想着用#define kScaleWidth(width) (width) * (SCREEN_WIDTH / 375.f)这个宏处理,还是不好使。

px:像素 pt:独立像素 / point / 点 iOS 开发中用到的单位 pt 是独立像素的意思,它是绝对长度,不随屏幕像素密度变化而变化。 ——

罪魁祸首就是像素,手机屏幕最小的单位是像素也就是1px,当小于1px时,像素是不可再分的,就造成了上面的现象。所以用宏处理,如果要求精确,还是不能使。(上面的课程表就因为上面部分留的位置太少,要求精确)

换言之,即使view的Size能设为小数,也可能会丢失部分小数。

由于px不可再分,,在1px=0.5pt的屏幕中,按0.5pt划分。0.3pt也要占1px,0.8pt也要占2px。所以按那个宏来处理还是不行。

解决

  • 方案一 设置最大间隙

自定义UICollectionViewFlowLayout,重写layoutAttributesForElementsInRect方法。修改返回cell的frame。

// 实现这个方法,返回每个cell的布局属性。// Implement -layoutAttributesForElementsInRect: to return layout attributes for for supplementary or decoration views, or to perform layout in an as-needed-on-screen fashion.- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect; // return an array layout attributes instances for all the views in the given rect复制代码

网上看到这篇,没有给出垂直方向代码,而且有漏洞,测试如下。原因是 section0最后一个cell刚好换到上一行时,section1就应该往上偏移。


笔者针对这份代码做了优化,但笔者算法差劲,依然存在不少不足。如果一个section中有多个cell时,系统计算的frame可能会换几次行。但只要UI不是设计得特别复杂,是不会发生这种情况的。

// CourseFlowLayout.h@interface CourseFlowLayout : UICollectionViewFlowLayout- (instancetype)initWithMaxSpacing:(NSInteger)maxSpacing;@end复制代码
// CourseFlowLayout.m- (NSArray
*)layoutAttributesForElementsInRect:(CGRect)rect{ NSMutableArray
*attributes = [[super layoutAttributesForElementsInRect:rect] mutableCopy]; if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {// 水平布局 float contentSizeWidth = self.collectionViewContentSize.width; float offset = 0;// 记录偏移量 for(int i = 1; i < attributes.count; i++){ UICollectionViewLayoutAttributes *currentLayoutAttributes = attributes[i]; UICollectionViewLayoutAttributes *prevLayoutAttributes = attributes[i - 1]; CGRect newFrame = currentLayoutAttributes.frame; {// 修改y newFrame.origin.y -= offset; } {// 修改y // 处理多section,如果是item == 0,x不做处理 NSInteger curIndexItem = currentLayoutAttributes.indexPath.item; if (curIndexItem == 0) { currentLayoutAttributes.frame = newFrame; continue; } // 取上一个cell的底部 NSInteger prevorigin = CGRectGetMaxY(prevLayoutAttributes.frame); // 还够位置就设置x if(prevorigin + _maxSpacing + WIDTH(currentLayoutAttributes) <= contentSizeWidth) {// 假设cell放进去是否会超过collectionView的右边 newFrame.origin.x = prevorigin + _maxSpacing; // 跟系统算出来的对比 是否换行了 // 如果section最后一item换行 意味着后面的y都要减回去 if (Y(currentLayoutAttributes) != Y(prevLayoutAttributes)) { if (i < attributes.count - 1) { if (attributes[i + 1].indexPath.section != currentLayoutAttributes.indexPath.section) { offset += Y(currentLayoutAttributes) - Y(prevLayoutAttributes); } } newFrame.origin.y = Y(prevLayoutAttributes); } } else {// 不够位置x设为0,摆在另一行首部 newFrame.origin.x = 0; } } currentLayoutAttributes.frame = newFrame; } } else {// 垂直布局 float contentSizeHeight = self.collectionViewContentSize.height; float offset = 0;// 记录偏移量 for(int i = 1; i < attributes.count; i++){ UICollectionViewLayoutAttributes *currentLayoutAttributes = attributes[i]; UICollectionViewLayoutAttributes *prevLayoutAttributes = attributes[i - 1]; CGRect newFrame = currentLayoutAttributes.frame; {// 修改x newFrame.origin.x -= offset; } {// 修改y // 处理多section,如果是item == 0,y不做处理 NSInteger curIndexItem = currentLayoutAttributes.indexPath.item; if (curIndexItem == 0) { currentLayoutAttributes.frame = newFrame; continue; } // 取上一个cell的底部 NSInteger prevorigin = CGRectGetMaxY(prevLayoutAttributes.frame); // 还够位置就设置y if(prevorigin + _maxSpacing + HEIGHT(currentLayoutAttributes) <= contentSizeHeight) {// 假设cell放进去是否会超过collectionView的底部 newFrame.origin.y = prevorigin + _maxSpacing; // 跟系统算出来的对比 是否换列了 // 如果section最后一item换列 意味着后面的x都要减回去 if (X(currentLayoutAttributes) != X(prevLayoutAttributes)) { if (i < attributes.count - 1) { if (attributes[i + 1].indexPath.section != currentLayoutAttributes.indexPath.section) { offset += X(currentLayoutAttributes) - X(prevLayoutAttributes); } } newFrame.origin.x = X(prevLayoutAttributes); } } else {// 不够位置y设为0,摆在另一列首部 newFrame.origin.y = 0; } } currentLayoutAttributes.frame = newFrame; } } return attributes;}复制代码

代码效果如下。

  • 还找到一种方案二

该方案用到了屏幕像素,可以达到无缝或者1px细缝的精致效果。改动下应该也能实现间隙的控制。

转载地址:http://wzsuo.baihongyu.com/

你可能感兴趣的文章
与众不同 windows phone (40) - 8.0 媒体: 音乐中心的新增功能, 图片中心的新增功能, 后台音乐播放的新增功能...
查看>>
Jenkins学习七:Jenkins的授权和访问控制
查看>>
PowerDesigner将PDM导出生成WORD文档(转)
查看>>
路由器扫描的Java源码
查看>>
Android经常使用的五种弹出对话框
查看>>
经常使用命令 echo、@、call、pause、rem
查看>>
Activity的启动模式详解
查看>>
[改善Java代码]构造函数尽量简化
查看>>
优化PHP程序的方法(温故知新)
查看>>
阿里开源Mysql分布式中间件:Cobar
查看>>
JavaScript对数组的处理(一)
查看>>
[iBoard 电子学堂][第八卷 设计任意波发生器]第一篇 iBoard 任意波发生器简介
查看>>
[iBoard 电子学堂][第〇卷 电子基础]第二篇 电路图与印刷电路板
查看>>
配置JAVA环境
查看>>
java环境变量
查看>>
浅谈API设计
查看>>
java----OO的概念和设计原则(转)
查看>>
Java 实现 淘宝秒杀 聚划算 自己主动提醒 源代码
查看>>
如何下载一个物种的全部EST序列 | NCBI | 表达序列标签
查看>>
代码编辑器Sublime Text 3 免费使用方法与简体中文汉化包下载
查看>>