奇怪的 UICollectionViewCell 行为如果浮动大小
Strange UICollectionViewCell behaviour if float size
更新:
示例项目是 github link
使用iPHONE 6模拟器
实现此错误的 2 种可能方法。
只需构建 运行 即可查看。
或者取消注释 256 行
//return CGSizeMake(widthAndHeight * self.venueLayoutZoom, widthAndHeight * self.venueLayoutZoom);
并按下 "Remove column" 按钮
我有 UICollectionView
和很多 UICollectionViewCell
。我的 UI 让我在单元格之间使用零 space。我的 UICollectionView
中有一个 pinch
手势。所以有时 sizeForItem:atIndexPath:
returns 给我一个很大的浮点数(比如 11.821123411231)。问题是:
如果我不舍入这些浮点数,我有时会出现奇怪的行为 -
应该是
如果我向上或向下舍入 sizeForItem:atIndexPath:
它看起来不错但是单元格之间有 spaces
我不知道该怎么办。没有这些 space 或奇怪的单元格真的很有必要。
我的流程布局是 this
控制器代码:
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(nonnull NSIndexPath *)indexPath
{
CGFloat widthAndHeight = [self widthAndHeightForCollectionView:collectionView];
CGFloat result = widthAndHeight * self.venueLayoutZoom;
return CGSizeMake(result, result);
}
- (void)didReceivePinchGesture:(UIPinchGestureRecognizer *)gesture
{
static CGFloat scaleStart;
if (gesture.state == UIGestureRecognizerStateBegan) {
scaleStart = self.venueLayoutZoom;
}
else if (gesture.state == UIGestureRecognizerStateChanged) {
self.venueLayoutZoom = scaleStart * gesture.scale;
}
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
VenueLayoutCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kVenueLayoutCellReuseIdentifier forIndexPath:indexPath];
self.activeCollectionViewCellsDictionary[indexPath] = cell;
if (self.activeCollectionViewObjects.count > indexPath.section) {
NSArray *rows = self.activeCollectionViewObjects[indexPath.section];
if (rows.count > indexPath.row) {
if ([rows[indexPath.row] isKindOfClass:[VenueLayoutCellObject class]]) {
VenueLayoutCellObject *object = rows[indexPath.row];
cell.cellObject = object;
}
}
}
return cell;
}
单元格代码:
@property (nonatomic, strong) CALayer *circularLayer;
- (void)awakeFromNib
{
[super awakeFromNib];
[self allocAndAddLayers];
}
- (void)allocAndAddLayers
{
self.circularLayer = [CALayer layer];
[self.layer addSublayer:self.circularLayer];
}
#pragma mark - Property Set
- (void)setCellObject:(VenueLayoutCellObject *)cellObject
{
self->_cellObject = cellObject;
self.objectBackgroundColor = cellObject.objectColor;
self.type = cellObject.type;
}
- (void)prepareForReuse
{
[self.circularLayer removeFromSuperlayer];
[self allocAndAddLayers];
}
- (void)setType:(VenueLayoutObjectType)type
{
self->_type = type;
[self updateInderfaceDependOnType];
}
- (void)layoutSubviews
{
[CATransaction begin];
[CATransaction setDisableActions:YES];
[self updateRoundedCorners];
[CATransaction commit];
[super layoutSubviews];
}
- (void)updateRoundedCorners
{
CGRect bounds = self.bounds;
CGRect frame = self.frame;
self.circularLayer.frame = CGRectMake(0, 0, frame.size.width, frame.size.height);
}
- (void)setLayerBackgroundColor:(UIColor *)color
{
self.circularLayer.backgroundColor = color.CGColor;
self.objectMaskLayer.strokeColor = color.CGColor;
self.deselectedColor = color;
}
- (void)updateInderfaceDependOnType
{
UIColor *tempObjectColor = [UIColor grayColor];
UIColor *objectColor = self.objectBackgroundColor ? : tempObjectColor;
[self setLayerBackgroundColor:objectColor];
}
更新代码:
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(nonnull NSIndexPath *)indexPath
{
CGFloat widthAndHeight = self.widthAndHeightForActiveCollectionView;
CGFloat result = lroundf(widthAndHeight * self.venueLayoutZoom);
CGFloat width = result;
if (indexPath.row > self.increasedWidthInitialIndex) {
width++;
}
return CGSizeMake(width, result);
}
CGFloat widthAndHeight = CGRectGetWidth(self.activeCollectionView.bounds) / maxCount;
NSNumber *widthNumber = @(CGRectGetWidth(self.activeCollectionView.bounds));
NSInteger count = widthNumber.integerValue % maxCount;
maxCount--;
self.increasedWidthInitialIndex = maxCount - count;
更新:
如果我使用较小的项目大小(例如 CGSizeMake(7.f, 7.f)
),单元格不适合整个
集合视图,但 space 仍然存在
最终将宽度/高度设置为半像素会根据设备像素深度更改比例(视网膜对比 non-retina)- 更多信息 here
当您尝试将屏幕划分为 non-whole 个数字时,即对于 320 的屏幕宽度,创建 6 个 53.3 的单元格可能会导致 UI 中断。
你应该试着找到你的剩余部分,即:
320 % 6 -> 2
然后将 2 个单元格加宽 1 个像素。
因此,不是由 53.3 像素宽组成的 6 个单元格,而是 2 个由 54 像素组成的单元格和另外 4 个由 53 像素组成的单元格,然后一切都会正确。
编辑:
检查完你的项目后,我添加了你的打印输出 collection 看看宽度可能导致什么问题,我在 ViewController.m:
中添加了这个方法
- (void)printoutGrid
{
NSLog(@"collectionview bounds: %f, %@", self.activeCollectionView.bounds.size.width, NSStringFromCGSize(self.activeCollectionView.contentSize));
CGFloat calculatedWidth = [self widthAndHeightForActiveCollectionViewItem];
CGFloat result = floor(calculatedWidth * self.venueLayoutZoom);
for (int rowAt = 0; rowAt < self.activeCollectionViewObjects.count; rowAt++)
{
NSArray* arrayAt = self.activeCollectionViewObjects[rowAt];
NSString* rowString = @"|";
for (int colAt = 0; colAt < arrayAt.count; colAt++)
{
if (colAt > self.increasedWidthInitialIndex)
{
rowString = [rowString stringByAppendingString:[NSString stringWithFormat:@"%d|", (int)result + 1]];
}
else
{
rowString = [rowString stringByAppendingString:[NSString stringWithFormat:@"%d|", (int)result]];
}
}
NSLog(@"%@", rowString);
}
}
并在每次重新加载 collection 或使布局无效后调用它,我只发现您应该使用 floor 而不是 lroundf。
此方法将帮助您为将来调试宽度。
但是,在检查了您的项目设置后,您的模拟器中似乎出现了问题,我注意到它太大/超出比例并且不是视网膜,我进入了您的项目设置并发现您的项目与视网膜不兼容- 这意味着 UI 不会使用 Auto-Scaling -> 这意味着它将对所有设备使用相同的分辨率 (320 x 518) 以及它的作用,它延伸了 UI - 意思在 iPhone 6 中它乘以它,并且拉伸是 anti-analysed,这导致这些 so-called 单元格之间的空 spaces 即使那里没有 space .
您需要做的是转到项目设置 -> 通常向下滚动到列表中的 "Launch Screen File" 和 select "LaunchScreen":
这似乎解决了这个项目的问题。如果您还有任何问题以及它是否有效,请告诉我。
请注意 - 这将要求您更改大小计算 a-bit,因为分辨率会在 "viewDidLayoutSubviews" 之后再次更改,而不仅仅是在加载视图时。
祝你好运!
更新: 示例项目是 github link
使用iPHONE 6模拟器
实现此错误的 2 种可能方法。 只需构建 运行 即可查看。 或者取消注释 256 行
//return CGSizeMake(widthAndHeight * self.venueLayoutZoom, widthAndHeight * self.venueLayoutZoom);
并按下 "Remove column" 按钮
我有 UICollectionView
和很多 UICollectionViewCell
。我的 UI 让我在单元格之间使用零 space。我的 UICollectionView
中有一个 pinch
手势。所以有时 sizeForItem:atIndexPath:
returns 给我一个很大的浮点数(比如 11.821123411231)。问题是:
如果我不舍入这些浮点数,我有时会出现奇怪的行为 -
应该是
如果我向上或向下舍入 sizeForItem:atIndexPath:
它看起来不错但是单元格之间有 spaces
我不知道该怎么办。没有这些 space 或奇怪的单元格真的很有必要。 我的流程布局是 this
控制器代码:
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(nonnull NSIndexPath *)indexPath
{
CGFloat widthAndHeight = [self widthAndHeightForCollectionView:collectionView];
CGFloat result = widthAndHeight * self.venueLayoutZoom;
return CGSizeMake(result, result);
}
- (void)didReceivePinchGesture:(UIPinchGestureRecognizer *)gesture
{
static CGFloat scaleStart;
if (gesture.state == UIGestureRecognizerStateBegan) {
scaleStart = self.venueLayoutZoom;
}
else if (gesture.state == UIGestureRecognizerStateChanged) {
self.venueLayoutZoom = scaleStart * gesture.scale;
}
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
VenueLayoutCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kVenueLayoutCellReuseIdentifier forIndexPath:indexPath];
self.activeCollectionViewCellsDictionary[indexPath] = cell;
if (self.activeCollectionViewObjects.count > indexPath.section) {
NSArray *rows = self.activeCollectionViewObjects[indexPath.section];
if (rows.count > indexPath.row) {
if ([rows[indexPath.row] isKindOfClass:[VenueLayoutCellObject class]]) {
VenueLayoutCellObject *object = rows[indexPath.row];
cell.cellObject = object;
}
}
}
return cell;
}
单元格代码:
@property (nonatomic, strong) CALayer *circularLayer;
- (void)awakeFromNib
{
[super awakeFromNib];
[self allocAndAddLayers];
}
- (void)allocAndAddLayers
{
self.circularLayer = [CALayer layer];
[self.layer addSublayer:self.circularLayer];
}
#pragma mark - Property Set
- (void)setCellObject:(VenueLayoutCellObject *)cellObject
{
self->_cellObject = cellObject;
self.objectBackgroundColor = cellObject.objectColor;
self.type = cellObject.type;
}
- (void)prepareForReuse
{
[self.circularLayer removeFromSuperlayer];
[self allocAndAddLayers];
}
- (void)setType:(VenueLayoutObjectType)type
{
self->_type = type;
[self updateInderfaceDependOnType];
}
- (void)layoutSubviews
{
[CATransaction begin];
[CATransaction setDisableActions:YES];
[self updateRoundedCorners];
[CATransaction commit];
[super layoutSubviews];
}
- (void)updateRoundedCorners
{
CGRect bounds = self.bounds;
CGRect frame = self.frame;
self.circularLayer.frame = CGRectMake(0, 0, frame.size.width, frame.size.height);
}
- (void)setLayerBackgroundColor:(UIColor *)color
{
self.circularLayer.backgroundColor = color.CGColor;
self.objectMaskLayer.strokeColor = color.CGColor;
self.deselectedColor = color;
}
- (void)updateInderfaceDependOnType
{
UIColor *tempObjectColor = [UIColor grayColor];
UIColor *objectColor = self.objectBackgroundColor ? : tempObjectColor;
[self setLayerBackgroundColor:objectColor];
}
更新代码:
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(nonnull NSIndexPath *)indexPath
{
CGFloat widthAndHeight = self.widthAndHeightForActiveCollectionView;
CGFloat result = lroundf(widthAndHeight * self.venueLayoutZoom);
CGFloat width = result;
if (indexPath.row > self.increasedWidthInitialIndex) {
width++;
}
return CGSizeMake(width, result);
}
CGFloat widthAndHeight = CGRectGetWidth(self.activeCollectionView.bounds) / maxCount;
NSNumber *widthNumber = @(CGRectGetWidth(self.activeCollectionView.bounds));
NSInteger count = widthNumber.integerValue % maxCount;
maxCount--;
self.increasedWidthInitialIndex = maxCount - count;
更新:
如果我使用较小的项目大小(例如 CGSizeMake(7.f, 7.f)
),单元格不适合整个
集合视图,但 space 仍然存在
最终将宽度/高度设置为半像素会根据设备像素深度更改比例(视网膜对比 non-retina)- 更多信息 here
当您尝试将屏幕划分为 non-whole 个数字时,即对于 320 的屏幕宽度,创建 6 个 53.3 的单元格可能会导致 UI 中断。
你应该试着找到你的剩余部分,即:
320 % 6 -> 2
然后将 2 个单元格加宽 1 个像素。 因此,不是由 53.3 像素宽组成的 6 个单元格,而是 2 个由 54 像素组成的单元格和另外 4 个由 53 像素组成的单元格,然后一切都会正确。
编辑:
检查完你的项目后,我添加了你的打印输出 collection 看看宽度可能导致什么问题,我在 ViewController.m:
中添加了这个方法- (void)printoutGrid
{
NSLog(@"collectionview bounds: %f, %@", self.activeCollectionView.bounds.size.width, NSStringFromCGSize(self.activeCollectionView.contentSize));
CGFloat calculatedWidth = [self widthAndHeightForActiveCollectionViewItem];
CGFloat result = floor(calculatedWidth * self.venueLayoutZoom);
for (int rowAt = 0; rowAt < self.activeCollectionViewObjects.count; rowAt++)
{
NSArray* arrayAt = self.activeCollectionViewObjects[rowAt];
NSString* rowString = @"|";
for (int colAt = 0; colAt < arrayAt.count; colAt++)
{
if (colAt > self.increasedWidthInitialIndex)
{
rowString = [rowString stringByAppendingString:[NSString stringWithFormat:@"%d|", (int)result + 1]];
}
else
{
rowString = [rowString stringByAppendingString:[NSString stringWithFormat:@"%d|", (int)result]];
}
}
NSLog(@"%@", rowString);
}
}
并在每次重新加载 collection 或使布局无效后调用它,我只发现您应该使用 floor 而不是 lroundf。
此方法将帮助您为将来调试宽度。
但是,在检查了您的项目设置后,您的模拟器中似乎出现了问题,我注意到它太大/超出比例并且不是视网膜,我进入了您的项目设置并发现您的项目与视网膜不兼容- 这意味着 UI 不会使用 Auto-Scaling -> 这意味着它将对所有设备使用相同的分辨率 (320 x 518) 以及它的作用,它延伸了 UI - 意思在 iPhone 6 中它乘以它,并且拉伸是 anti-analysed,这导致这些 so-called 单元格之间的空 spaces 即使那里没有 space .
您需要做的是转到项目设置 -> 通常向下滚动到列表中的 "Launch Screen File" 和 select "LaunchScreen":
这似乎解决了这个项目的问题。如果您还有任何问题以及它是否有效,请告诉我。
请注意 - 这将要求您更改大小计算 a-bit,因为分辨率会在 "viewDidLayoutSubviews" 之后再次更改,而不仅仅是在加载视图时。
祝你好运!