UICollectionView对齐逻辑中缺少水平滚动视图寻呼(UICollectionView a

2019-07-03 14:19发布

我有一个UICollectionView ,直到我开始滚动,其工作正常。 这里是一些图片第一:

正如你可以看到它的伟大。 当我开始滚动(启用分页)第一个进入了一下屏幕外:

这就是问题。 渊源我认为有3次,我想滚动,只显示3次。 但是,因为它滚动(启用分页),它隐藏了第一种观点的一点点,展现从下一页的下一个第一种观点的一点。

这里是一个视频,因为它是有点难以解释: 问题的视频(Dropbox的)

这里是我的照片UICollectionView设置:

这将是巨大的,如果有人能帮助!

Answer 1:

最根本的问题是流式布局并非设计用于支持分页。 为了实现分页效果,你将不得不牺牲细胞之间的空间。 并仔细计算单元框架,使其能够通过集合视图帧没有余数来划分。 我会解释原因。

话说以下布局正是你想要的。

请注意,最左边空白处(绿色)不是单元格间距的一部分。 它是由流布局部插入确定。 由于流布局不支持异构间距值。 这不是一个简单的任务。

因此,设置的间隔和插入后。 下面的布局你会得到什么。

滚动到下一个页面之后。 你的细胞显然不对齐,你所期望的。

使单元格间距0就可以解决这个问题。 但是,如果你想在页面上的额外余量,特别是如果保证金是从单元格间距不同它限制了你的设计。 它还要求视图帧必须是由所述单元框整除。 有时,如果您的视图帧不固定(考虑旋转情况)的疼痛。

真正的解决办法是继承UICollectionViewFlowLayout并覆盖下面的方法

- (CGSize)collectionViewContentSize
{
    // Only support single section for now.
    // Only support Horizontal scroll 
    NSUInteger count = [self.collectionView.dataSource collectionView:self.collectionView
                                               numberOfItemsInSection:0];

    CGSize canvasSize = self.collectionView.frame.size;
    CGSize contentSize = canvasSize;
    if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal)
    {
        NSUInteger rowCount = (canvasSize.height - self.itemSize.height) / (self.itemSize.height + self.minimumInteritemSpacing) + 1;
        NSUInteger columnCount = (canvasSize.width - self.itemSize.width) / (self.itemSize.width + self.minimumLineSpacing) + 1;
        NSUInteger page = ceilf((CGFloat)count / (CGFloat)(rowCount * columnCount));
        contentSize.width = page * canvasSize.width;
    }

    return contentSize;
}


- (CGRect)frameForItemAtIndexPath:(NSIndexPath *)indexPath
{
    CGSize canvasSize = self.collectionView.frame.size;

    NSUInteger rowCount = (canvasSize.height - self.itemSize.height) / (self.itemSize.height + self.minimumInteritemSpacing) + 1;
    NSUInteger columnCount = (canvasSize.width - self.itemSize.width) / (self.itemSize.width + self.minimumLineSpacing) + 1;

    CGFloat pageMarginX = (canvasSize.width - columnCount * self.itemSize.width - (columnCount > 1 ? (columnCount - 1) * self.minimumLineSpacing : 0)) / 2.0f;
    CGFloat pageMarginY = (canvasSize.height - rowCount * self.itemSize.height - (rowCount > 1 ? (rowCount - 1) * self.minimumInteritemSpacing : 0)) / 2.0f;

    NSUInteger page = indexPath.row / (rowCount * columnCount);
    NSUInteger remainder = indexPath.row - page * (rowCount * columnCount);
    NSUInteger row = remainder / columnCount;
    NSUInteger column = remainder - row * columnCount;

    CGRect cellFrame = CGRectZero;
    cellFrame.origin.x = pageMarginX + column * (self.itemSize.width + self.minimumLineSpacing);
    cellFrame.origin.y = pageMarginY + row * (self.itemSize.height + self.minimumInteritemSpacing);
    cellFrame.size.width = self.itemSize.width;
    cellFrame.size.height = self.itemSize.height;

    if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal)
    {
        cellFrame.origin.x += page * canvasSize.width;
    }

    return cellFrame;
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewLayoutAttributes * attr = [super layoutAttributesForItemAtIndexPath:indexPath];
    attr.frame = [self frameForItemAtIndexPath:indexPath];
    return attr;
}

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    NSArray * originAttrs = [super layoutAttributesForElementsInRect:rect];
    NSMutableArray * attrs = [NSMutableArray array];

    [originAttrs enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes * attr, NSUInteger idx, BOOL *stop) {
        NSIndexPath * idxPath = attr.indexPath;
        CGRect itemFrame = [self frameForItemAtIndexPath:idxPath];
        if (CGRectIntersectsRect(itemFrame, rect))
        {
            attr = [self layoutAttributesForItemAtIndexPath:idxPath];
            [attrs addObject:attr];
        }
    }];

    return attrs;
}

通知,上述代码段中只支持单节和水平滚动的方向。 但也不是很难扩大。

另外,如果你没有数百万个细胞。 缓存那些UICollectionViewLayoutAttributes可能是一个好主意。



Answer 2:

你可以在UICollectionView禁用分页并实现了自定义页面宽度/像这样的偏移的自定义水平滚动条/分页机制:

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
    float pageWidth = 210;

    float currentOffset = scrollView.contentOffset.x;
    float targetOffset = targetContentOffset->x;
    float newTargetOffset = 0;

    if (targetOffset > currentOffset)
        newTargetOffset = ceilf(currentOffset / pageWidth) * pageWidth;
    else
        newTargetOffset = floorf(currentOffset / pageWidth) * pageWidth;

    if (newTargetOffset < 0)
        newTargetOffset = 0;
    else if (newTargetOffset > scrollView.contentSize.width)
        newTargetOffset = scrollView.contentSize.width;

    targetContentOffset->x = currentOffset;
    [scrollView setContentOffset:CGPointMake(newTargetOffset, 0) animated:YES];
}


Answer 3:

这个答案是这样晚了,但我刚才一直在玩这个问题,发现漂移的原因是行间距 。 如果你想UICollectionView /的FlowLayout页的整倍数的你的细胞宽度,必须设置:

UICollectionViewFlowLayout *flowLayout = (UICollectionViewFlowLayout *)collectionView.collectionViewLayout;
flowLayout.minimumLineSpacing = 0.0;

你不会觉得行距进入在水平滚动播放,但显然它。

在我来说,我与寻呼同时从左到右,一个细胞实验,与细胞之间没有空格。 页面动辄推出漂移的一点点从期望的位置,并且它似乎线性积累。 〜每匝10.0 PTS。 我意识到10.0 minimumLineSpacing在流布局的默认值。 当我将它设置为0.0,无漂移,当我把它设置为界限宽度的一半,每个页面漂流边界的一个额外的一半。

更改minimumInteritemSpacing 没有影响

编辑-从文件UICollectionViewFlowLayout :

@属性(非原子)CGFloat的minimumLineSpacing;

讨论

...

对于垂直滚动网格,该值表示连续行之间的最小间距。 为水平滚动的网格,该值表示连续列之间的最小间距。 该间距不施加到集管和第一线之间或最后一行和页脚之间的空间。

此属性的默认值是10.0。



Answer 4:

从下面的文章的解决方案是优雅而简洁。 其主要思想是创造了滚动与传递所有contentOffset值你的CollectionView的顶部。

http://b2cloud.com.au/tutorial/uiscrollview-paging-size/

应该通过实施该方法来表示:

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity;

像它与pagingEnabled发生我没有实现平滑的动画= YES。



Answer 5:

我知道这个问题是旧的,但任何人谁发生在此绊倒。

所有你需要做的正确的,这是设置MinimumInterItemSpacing为0,降低内容的框架。



Answer 6:

我想我明白这个问题。 我会试着让你明白这一点。

如果你仔细观察,你会看到,这个问题只发生逐渐而不是只在第一页上刷卡。

如果我理解正确的话,在你的应用程序,目前,每UICollectionView项目是那些圆形的盒子,我们看到,你有所有的人之间的一些偏移/利润是不变的。 这是什么原因造成的问题。

相反,你应该做的,是让一个UICollectionView项目是整个视图的宽度的1/3,然后添加里面圆润的图像视图。 来指代图像,绿色应该是你UICollectionViewItem,而不是黑色的。



Answer 7:

@devdavid是当场上的flowLayout.minimumLineSpacing为零。

它也可以在布局编辑器完成,线路设置最小间距为0:



Answer 8:

你滚你自己UICollectionViewFlowLayout

如果是这样,加入-(CGPoint) targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity将帮助您计算在滚动视图应该停止。

这可能会实现(注:UNTESTED!):

-(CGPoint) targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset
                             withScrollingVelocity:(CGPoint)velocity
{
  CGFloat offsetAdjustment = MAXFLOAT;
  CGFloat targetX = proposedContentOffset.x + self.minimumInteritemSpacing + self.sectionInset.left;

  CGRect targetRect = CGRectMake(proposedContentOffset.x, 0.0, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);

  NSArray *array = [super layoutAttributesForElementsInRect:targetRect];
  for(UICollectionViewLayoutAttributes *layoutAttributes in array) {

    if(layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) {
      CGFloat itemX = layoutAttributes.frame.origin.x;

      if (ABS(itemX - targetX) < ABS(offsetAdjustment)) {
        offsetAdjustment = itemX - targetX;
      }
    }
  }

  return CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y);
}


Answer 9:

我的答案是基于答案https://stackoverflow.com/a/27242179/440168但更简单。

您应该将UIScrollView上述UICollectionView ,给他们平等的大小:

@property (nonatomic, weak) IBOutlet UICollectionView *collectionView;
@property (nonatomic, weak) IBOutlet UIScrollView *scrollView;

然后配置contentInset集合视图,例如:

CGFloat inset = self.view.bounds.size.width*2/9;
self.collectionView.contentInset = UIEdgeInsetsMake(0, inset, 0, inset);

contentSize滚动视图:

self.scrollView.contentSize = CGSizeMake(self.placesCollectionView.bounds.size.width*[self.collectionView numberOfItemsInSection:0],0);

不要忘记设置滚动视图的委托:

self.scrollView.delegate = self;

并实施主要法宝:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (scrollView == self.scrollView) {
        CGFloat inset = self.view.bounds.size.width*2/9;
        CGFloat scale = (self.placesCollectionView.bounds.size.width-2*inset)/scrollView.bounds.size.width;
        self.collectionView.contentOffset = CGPointMake(scrollView.contentOffset.x*scale - inset, 0);
    }
}


Answer 10:

UICollectionView的宽度应在单元尺寸宽度+左,右插图的准确乘法。 在示例中,如果单元宽度为96,则UICollectionView的宽度应为(96 + 5 + 5) * 3 = 318 。 或者,如果你想保留UICollectionView的320宽度,你的单元尺寸宽度应320 / 3 - 5 - 5 = 96.666

如果这没有帮助,你UICollectionView的宽度可能比什么是在厦门国际银行文件中设置,应用程序运行时不同。 要检查这一点-添加NSLog声明印出视图的大小在运行时:

NSLog(@"%@", NSStringFromCGRect(uiContentViewController.view.frame));


Answer 11:

这是我遇到同样的问题,我贴在另一篇文章中我的解决方案,所以我在这里再次张贴。

我发现了一个解决的办法,这涉及继承的UICollectionViewFlowLayout。

我的CollectionViewCell大小是302 X 457和设置我的最小线间距为18(9pix针对每个小区)

当您从类扩展有需要将超过缠身的一些方法。 其中之一是

  • (CGSize)collectionViewContentSize

在这种方法中,我需要添加了什么是在UICollectionView总宽度。 这包括([数据源计数] * widthOfCollectionViewCell)+([数据源计数] * 18)

这里是我的自定义UICollectionViewFlowLayout方法....

-(id)init
{
    if((self = [super init])){

       self.itemSize = CGSizeMake(302, 457);
       self.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);
       self.minimumInteritemSpacing = 0.0f;
       self.minimumLineSpacing = 18.0f;
       [self setScrollDirection:UICollectionViewScrollDirectionHorizontal];
   }
    return self;
}



-(CGSize)collectionViewContentSize{
   return CGSizeMake((numCellsCount * 302)+(numCellsCount * 18), 457);
}

这为我工作,所以我希望别人发现它有用!



Answer 12:

您还可以设置视图的以“320 +间距”,然后设置页面宽度能够为yes。 它会滚动“320 +空间”的每一次。 我想这是因为页面能够将滚动视图的宽度,但没有屏幕的宽度。



Answer 13:

我觉得我有这个问题的解决方案。 但我不,如果这是最好的。

UICollectionViewFlowLayout确实含有一种叫做财产sectionInset 。 所以,你可以设置部分内陷,以任何你需要的是,让1页等于一个部分。 因此,你的滚动应该自动适应正常的网页(=部分)



Answer 14:

我曾与分页类似的问题。 即使电池插图均为0,细胞正是在宽度和高度的大小相同UICollectionView ,寻呼是不妥当的。

我注意到像一个错误的声音在这个版本( UICollectionView ,iOS 6中):我可以看到,如果我有工作UICollectionView与宽度= 310px以上,高度= 538px,我遇到了麻烦。 但是,如果我减少宽度,比方说,300像素(高度相同),我得到的东西完美地工作!

对于一些未来的参考,我希望它能帮助!



Answer 15:

试图让水平分页对细胞的第插图和细胞及线间距为3×3格工作时,我遇到类似的问题。

对我来说,答案(尝试的许多建议后 - 包括继承UICollectionViewFlowLayout和各种UIScrollView的委托解决方案)很简单。 我只是打破我的数据集成的9个项目(或更少)的部分,并利用numberOfSectionsInCollectionView和numberOfItemsInSection UICollectionView数据源的方法使用的部分在UICollectionView。

该UICollectionView的水平分页现在精美的作品。 我推荐这种方法目前人撕扯自己的头发出过类似的情景。



Answer 16:

如果您使用的是默认流布局为您UICollectionView,不想每个单元之间的任何空间,你可以将其miniumumLineSpacing通过属性设置为0:

((UICollectionViewFlowLayout *) self.collectionView.collectionViewLayout).minimumLineSpacing = 0;


文章来源: UICollectionView align logic missing in horizontal paging scrollview