如果浮动大小,奇怪的 UICollectionViewCell 行为

Posted

技术标签:

【中文标题】如果浮动大小,奇怪的 UICollectionViewCell 行为【英文标题】:Strange UICollectionViewCell behaviour if float size 【发布时间】:2017-07-27 08:18:06 【问题描述】:

更新: 示例项目是github link

使用 iPhone 6 模拟器

实现此错误的两种可能方法。 只需构建并运行并查看。 或取消注释 256 行

//return CGSizeMake(widthAndHeight * self.venueLayoutZoom, widthAndHeight * self.venueLayoutZoom);

然后按“删除列”按钮

我有UICollectionView 和很多UICollectionViewCells。我的 UI 让我在单元格之间使用零空间。我的UICollectionView 中有一个pinch 手势。所以有时sizeForItem:atIndexPath: 会返回一个很大的浮点数(比如 11.821123411231)。问题是: 如果我不绕过这些花车,我有时会有一种奇怪的行为 -

应该是

如果我向上或向下取整 sizeForItem:atIndexPath: 它看起来不错,但单元格之间有空格

我不知道该怎么办。确实有必要不使用这些空间或奇怪的单元格。 我的流程布局是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))单元格不适合整个 集合视图,但空间仍然存在

【问题讨论】:

【参考方案1】:

最终将宽度/高度设置为半像素会根据设备像素深度(视网膜与非视网膜)更改比例 - 更多信息 here

当您尝试将屏幕划分为非整数时,即对于 320 的屏幕宽度,创建 6 个 53.3 的单元格可能会导致 UI 中断。

您应该尝试找到您的设计的其余部分,即:

320 % 6 -> 2

然后使 2 个单元格宽 1 个像素。 因此,您将拥有 2 个由 54 和 4 个 53 组成的单元,而不是 6 个由 53.3 像素宽组成的单元,然后一切都将正确拟合。

编辑:

查看您的项目后,我添加了您收藏的打印输出,看看宽度可能会导致什么问题,我在 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);
    

在每次重新加载集合或使布局无效后调用它,我发现只应该使用 floor 而不是 lroundf。

此方法将帮助您为将来调试宽度。

但是,在检查了您的项目设置后,您的模拟器中似乎有些问题,我注意到它太大/超出比例而不是视网膜,我去了您的项目设置并看到您的项目与视网膜不兼容 - 这意味着 UI 不会使用 Auto-Scaling -> 这意味着它将对所有设备使用相同的分辨率 (320 x 518) 以及它的作用,它会拉伸 UI - 这意味着在 iPhone 6 中它会乘以它,并且拉伸是反分析,即使那里没有空间,也会导致单元格之间出现这些所谓的空白空间。

您需要做的是转到您的项目设置 -> 通常向下滚动到“启动屏幕文件”并从列表中选择“启动屏幕”:

这似乎解决了这个项目的问题。让我知道您是否还有其他问题以及它是否有效。

请注意 - 这将需要您稍微更改尺寸计算,因为在“viewDidLayoutSubviews”之后分辨率会再次更改,而不仅仅是在视图加载时。

祝你好运!

【讨论】:

感谢您的回复。不工作:(如果我的缩放值为 1.2311231,我该怎么办,例如 你能告诉我你的 sizeForItem 的更新代码不起作用吗? 我已经更新了我的问题。在我的示例中,我一行中有 29 个项目。宽度是 320。 11 - 是圆角宽度。 11 * 28 + 12 = 320 结果如何?你还有空间吗?还是别的什么? 是的,还有 1 个空格。如果我放大 - 空间仍然存在

以上是关于如果浮动大小,奇怪的 UICollectionViewCell 行为的主要内容,如果未能解决你的问题,请参考以下文章

奇怪的 chrome 媒体查询行为

浮动操作按钮滚动奇怪的行为

浮动理解

在浮动导航栏中调整徽标大小

奇怪的浮动块包装在引导程序 3 col-* divs 列表中[重复]

CSS 上的浮动字体大小值如何在浏览器之间呈现?