UICollectionview 水平和垂直滚动 [英] UICollectionview scroll horizontal and vertical

查看:118
本文介绍了UICollectionview 水平和垂直滚动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须构建一个可水平和垂直滚动的 UICollectionView,我知道网格布局仅沿一个轴滚动,无论是水平还是垂直,所以我阅读了一些帖子并尝试了不同的解决方案,但最简单的是UIScrollView 中的 UICollectionview.这样,CollectionView 垂直滚动,UIScrollView 水平滚动.问题是垂直滚动很困难,不流畅并且经常停止,直到您再次点击并再次拖动.你能提出一个解决方案吗?谢谢

I have to build a UICollectionView scrollable horizontal and vertical, I know that the grid layout scrolls along one axis only, either horizontally or vertically, so I have read some posts and I have tried different solutions but the most simple is to put the UICollectionview inside a UIScrollView. In this way the CollectionView scroll vertically and the UIScrollView horizontally. The problem is that the vertical scroll is difficult, not fluid and often is stop until you tap again and drag again. Can you suggest a solution? Thanks

UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
UIScrollView *backgroundScroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
backgroundScroll.scrollEnabled = YES;     
[self.view addSubview:backgroundScroll];
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(10, 15, 1020, [UIScreen mainScreen].bounds.size.height - 35) collectionViewLayout:layout];
[backgroundScroll addSubview:_collectionView];
_collectionView.contentInset = UIEdgeInsetsMake(0, 0, 50, 0);         
_collectionView.scrollEnabled = YES;

而且我已经实现了这个方法:

And I have implemented the method:

- (void)viewDidLayoutSubviews {
    backgroundScroll.contentSize = self.collectionView.frame.size;
}

推荐答案

这样做的方法是创建一个自定义的 UICollectionViewLayout 子类.

The way to do this is to create a custom UICollectionViewLayout subclass.

我最近不得不这样做.

让我去拿文件...一秒钟...

Let me go get the files... One sec...

首先,您不能为此轻松使用 UICollectionViewFlowLayout 的子类.流布局旨在使内容在一个方向上适合并在另一个方向上滚动.这不是你想要的.

First of all, you can't use a subclass of UICollectionViewFlowLayout easily for this. Flow layout is designed to fit the content in one direction and scroll in the other direction. This isn't what you want.

虽然创建自定义布局来为您执行此操作并不难.

It isn't very difficult though to create a custom layout to do this for you.

头文件

@interface GridCollectionViewLayout : UICollectionViewLayout

// properties to configure the size and spacing of the grid
@property (nonatomic) CGSize itemSize;
@property (nonatomic) CGFloat itemSpacing;

// this method was used because I was switching between layouts    
- (void)configureCollectionViewForLayout:(UICollectionView *)collectionView;

@end

实施

#import "GridCollectionViewLayout.h"

@interface GridCollectionViewLayout ()

@property (nonatomic, strong) NSDictionary *layoutInfo;

@end

@implementation GridCollectionViewLayout

为代码和界面构建器创建初始化...

Create inits for code and interface builder...

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

    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];
    if (self) {
        [self setup];
    }

    return self;
}

设置默认属性值...

- (void)setup
{
    self.itemSize = CGSizeMake(50.0, 50.0);
    self.itemSpacing = 10.0;
}

使用它是因为我在不同的布局之间进行更改,但它显示了设置布局所需的内容..

This was used because I was changing between different layouts but it shows what is needed to set the layout..

- (void)configureCollectionViewForLayout:(UICollectionView *)collectionView
{
    collectionView.alwaysBounceHorizontal = YES;

    [collectionView setCollectionViewLayout:self animated:NO];
}

必需的方法.这将迭代项目并为每个项目创建框架 CGRect.将它们保存到字典中.

Required method. This iterates the items and creates frames CGRect for each one. Saving them into a dictionary.

- (void)prepareLayout
{
    NSMutableDictionary *cellLayoutInfo = [NSMutableDictionary dictionary];

    NSInteger sectionCount = [self.collectionView numberOfSections];
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];

    for (NSInteger section = 0; section < sectionCount; section++) {
        NSInteger itemCount = [self.collectionView numberOfItemsInSection:section];

        for (NSInteger item = 0; item < itemCount; item++) {
            indexPath = [NSIndexPath indexPathForItem:item inSection:section];

            UICollectionViewLayoutAttributes *itemAttributes =
            [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
            itemAttributes.frame = [self frameForAssessmentAtIndexPath:indexPath];

            cellLayoutInfo[indexPath] = itemAttributes;
        }
    }

    self.layoutInfo = cellLayoutInfo;
}

这是一种在给定索引处快速获取帧的便捷方法.

This is a convenience method for quickly getting a frame at a given index.

- (CGRect)frameForIndexPath:(NSIndexPath *)indexPath
{
    NSInteger column = indexPath.section;
    NSInteger row = indexPath.item;

    CGFloat originX = column * (self.itemSize.width + self.itemSpacing);
    CGFloat originY = row * (self.itemSize.height + self.itemSpacing);

    return CGRectMake(originX, originY, self.itemSize.width, self.itemSize.height);
}

计算内容大小所需的方法.这只是将部分或项目的数量乘以大小和间距属性.这是允许双向滚动的原因,因为内容大小可以大于集合视图的宽度和高度.

Required method to calculate the content size. This just multiplies the number of sections or items by the size and spacing properties. This is what allows scrolling in both directions because the content size can be bigger than the collection view's width AND height.

- (CGSize)collectionViewContentSize
{
    NSInteger sectionCount = [self.collectionView numberOfSections];

    if (sectionCount == 0) {
        return CGSizeZero;
    }

    NSInteger itemCount = [self.collectionView numberOfItemsInSection:0];

    CGFloat width = (self.itemSize.width + self.itemSpacing) * sectionCount - self.itemSpacing;
    CGFloat height = (self.itemSize.height + self.itemSpacing) * itemCount - self.itemSpacing;

    return CGSizeMake(width, height);
}

必需的方法.这些告诉集合视图需要放置每个项目的位置.

Required methods. These tell the collection view where each item needs to be placed.

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    return self.layoutInfo[indexPath];
}

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

    [self.layoutInfo enumerateKeysAndObjectsUsingBlock:^(NSIndexPath *indexPath, UICollectionViewLayoutAttributes *attributes, BOOL *stop) {
        if (CGRectIntersectsRect(attributes.frame, rect)) {
            [allAttributes addObject:attributes];
        }
    }];

    return allAttributes;
}

@end

当然,这种情况下的布局特定于我的个人问题.

Of course, the layout in this case is specific to my individual problem.

布局的工作原理是让每个部分都是一列,每个部分中的项目都是行.所以像这样......

The layout worked by having each section be a column and the items in each section were the rows. So something like this...

xy = item y in section x

00 10 20 30 ...
01 11 21 31 ...
02 12 22 32 ...
.  .  .  .
.  .  .  .
.  .  .  .

显然可以有无限数量的部分或部分中的项目,所以我必须在两个方向上滚动.

Obviously there can be an unlimited number of sections or items in sections so I had to have scrolling in both directions.

创建布局类后,只需将其设置为集合视图的布局即可.您可以在代码 collectionView.collectionViewLayout = myLayout 中执行此操作,也可以在 Interface Builder 中使用集合视图上的layout"属性执行此操作.

Once you have created your layout class you just need to set it as the layout for your collection view. You can do this in code collectionView.collectionViewLayout = myLayout or you can do it in Interface Builder with the "layout" property on the collection view.

这篇关于UICollectionview 水平和垂直滚动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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