UICollectionView水平分页scrollview中对齐逻辑丢失 [英] UICollectionView align logic missing in horizontal paging scrollview

查看:112
本文介绍了UICollectionView水平分页scrollview中对齐逻辑丢失的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



你可以看到它是伟大的。当我开始滚动(启用分页)第一个在屏幕外有点:$ b​​ $ b



这是问题。 Originaly我的视图有3个视图,我想滚动和只显示3个视图。但是当它滚动(分页启用)它隐藏一点点的第一个视图,并显示下一个第一个视图的一点点从下一页。



这里是一段视频,因为它很难解释:
问题视频(Dropbox)



这是我的 UICollectionView 设置:
>


解决方案

基本问题是流布局不是设计为支持分页。为了实现分页效果,你将不得不牺牲单元格之间的空间。仔细计算细胞框架,使其可以被收集视图框架除以没有余数。



https://i.stack.imgur.com/vetAp.jpgalt =enter image description here>



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



因此,在设置间距和插入后。





滚动到下一页。您的储存格显然不符合您的预期。





使单元格间距为0可以解决这个问题。但是,如果您希望页面上有额外的页边空间,特别是如果页边距与单元格间距不同,则会限制您的设计。它还要求视图框必须可被单元格框分割。有时,如果你的视图框架不是固定的(考虑旋转情况),这是一个痛苦。



真正的解决方案是子类化UICollectionViewFlowLayout并覆盖以下方法



   - (CGSize)collectionViewContentSize 
{
//现在只支持单节。
//只支持水平滚动
NSUInteger count = [self.collectionView.dataSource collectionView:self.collectionView
numberOfItemsInSection:0];

CGSize canvasSize = self.collectionView.frame.size;
CGSize contentSize = canvasSize;
if(self.scrollDirection == UICollectionViewScrollDirectionHorizo​​ntal)
{
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 == UICollectionViewScrollDirectionHorizo​​ntal)
{
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可能是个好主意。


I've got a UICollectionView, which works ok, until I start scrolling. Here some pics first:

As you can see it's great. As I start scrolling (paging enabled) the first one goes a bit offscreen:

This is the problem. Originaly my view have 3 views and I want to scroll and show 3 views only. But as it scrolls (paging enabled) it hides a little bit of the first view and show little bit of the next first view from the next page.

And here is a video, because it's kinda hard to explain: Video of the problem (Dropbox)

Here is a picture of my UICollectionView settings:

It's going to be great if someone can help!

解决方案

The fundamental issue is Flow Layout is not designed to support the paging. To achieve the paging effect, you will have to sacrifice the space between cells. And carefully calculate the cells frame and make it can be divided by the collection view frame without remainders. I will explain the reason.

Saying the following layout is what you wanted.

Notice, the most left margin (green) is not part of the cell spacing. It is determined by the flow layout section inset. Since flow layout doesn't support heterogeneous spacing value. It is not a trivial task.

Therefore, after setting the spacing and inset. The following layout is what you will get.

After scroll to next page. Your cells are obviously not aligned as what you expected.

Making the cell spacing 0 can solve this issue. However, it limits your design if you want the extra margin on the page, especially if the margin is different from the cell spacing. It also requires the view frame must be divisible by the cell frame. Sometimes, it is a pain if your view frame is not fixed (considering the rotation case).

The real solution is to subclass UICollectionViewFlowLayout and override following methods

- (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;
}

Notice, above code snippet only supports single section and horizontal scroll direction. But it is not hard to expand.

Also, if you don't have millions of cells. Caching those UICollectionViewLayoutAttributes may be a good idea.

这篇关于UICollectionView水平分页scrollview中对齐逻辑丢失的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆