草庐IT

ios - UICollectionview 水平和垂直滚动

coder 2024-01-19 原文

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

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;

我已经实现了这个方法:

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

最佳答案

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

我最近不得不这样做。

让我去拿文件...等一下...

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

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

头文件

@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

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

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

之所以使用它是因为我在不同的布局之间切换,但它显示了设置布局所需的内容..

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

    [collectionView setCollectionViewLayout:self animated:NO];
}

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

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

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

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

计算内容大小的必需方法。这只是将部分或项目的数量乘以大小和间距属性。这就是允许双向滚动的原因,因为内容大小可以大于 Collection View 的宽度和高度。

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

必需的方法。这些告诉 Collection View 每个项目需要放置的位置。

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

当然,这种情况下的布局是针对我个人的问题。

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

xy = item y in section x

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

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

创建布局类后,只需将其设置为 Collection View 的布局即可。您可以在代码 collectionView.collectionViewLayout = myLayout 中执行此操作,也可以在 Interface Builder 中使用 Collection View 上的“布局”属性执行此操作。

关于ios - UICollectionview 水平和垂直滚动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29302772/

有关ios - UICollectionview 水平和垂直滚动的更多相关文章

  1. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  2. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  3. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  4. ruby - 在 Ruby 中,垂直线是什么? - 2

    1.upto(9){|x|printx}为什么这行不通?{printx|x}}y呢? 最佳答案 它用于传递给您的block的参数。即在您的示例中,upto将使用1到9中的每个数字调用您的block,当前值可作为x获得。block参数可以有任何名称,就像方法参数一样。例如1.upto(9){|num|putsnum是有效的。就像一个方法的参数一样,一个block也可以有多个参数。例如hash.each_pair{|key,value|puts"#{key}is#{value}"} 关于ru

  5. ruby - 为什么不能使用类IO的实例方法noecho? - 2

    print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上

  6. ruby - 为 IO::popen 拯救 "command not found" - 2

    当我将IO::popen与不存在的命令一起使用时,我在屏幕上打印了一条错误消息:irb>IO.popen"fakefake"#=>#irb>(irb):1:commandnotfound:fakefake有什么方法可以捕获此错误,以便我可以在脚本中进行检查? 最佳答案 是:升级到ruby​​1.9。如果您在1.9中运行它,则会引发Errno::ENOENT,您将能够拯救它。(编辑)这是在1.8中的一种hackish方式:error=IO.pipe$stderr.reopenerror[1]pipe=IO.popen'qwe'#

  7. ruby-on-rails - Ruby on Rails 中的水平数据库扩展 - 2

    我有一个RubyonRails应用程序和一个具有以下结构的PostgreSQL数据库:classA只有几个A,而且增长缓慢(比如一个月5个)。每个A有数千个B,每个B有数万个C(因此每个A有数百万个C)。A是独立的,并且永远不会同时需要来自不同A的B和C(即在同一查询中)。我的问题是现在我只有几个A,ActiveRecord查询需要很长时间。当C的表有数千万行时,查询将永远无法进行。我正在考虑水平扩展数据库(即A的一张表,B的一张表和每个A的一张C的表)。但我不知道该怎么做。我猜这是一种分片,但我无法弄清楚如何动态创建数据库表并使用ActiveRecord访问数据(如果该表取决于我正在

  8. ruby - IO::EAGAINWaitReadable:资源暂时不可用 - 读取会阻塞 - 2

    当我尝试使用“套接字”库中的方法“read_nonblock”时出现以下错误IO::EAGAINWaitReadable:Resourcetemporarilyunavailable-readwouldblock但是当我通过终端上的IRB尝试时它工作正常如何让它读取缓冲区? 最佳答案 IgetthefollowingerrorwhenItrytousethemethod"read_nonblock"fromthe"socket"library当缓冲区中的数据未准备好时,这是预期的行为。由于异常IO::EAGAINWaitReadab

  9. ruby - 如何使用 ruby​​ fibers 避免阻塞 IO - 2

    我需要将目录中的一堆文件上传到S3。由于上传所需的90%以上的时间都花在了等待http请求完成上,所以我想以某种方式同时执行其中的几个。Fibers能帮我解决这个问题吗?它们被描述为解决此类问题的一种方法,但我想不出在http调用阻塞时我可以做任何工作的任何方法。有什么方法可以在没有线程的情况下解决这个问题? 最佳答案 我没有使用1.9中的纤程,但是1.8.6中的常规线程可以解决这个问题。尝试使用队列http://ruby-doc.org/stdlib/libdoc/thread/rdoc/classes/Queue.html查看文

  10. ruby - 如何从 ruby​​ 中的 IO 对象获取文件名 - 2

    在ruby中...我有一个由外部进程创建的IO对象,我需要从中获取文件名。然而我似乎只能得到文件描述符(3),这对我来说不是很有用。有没有办法从此对象获取文件名甚至获取文件对象?我正在从通知程序中获取IO对象。所以这也可能是获取文件路径的一种方式? 最佳答案 关于howtogetathefilenameinC也有类似的问题,我将在这里以ruby​​的方式给出这个问题的答案。在Linux中获取文件名假设io是您的IO对象。以下代码为您提供了文件名。File.readlink("/proc/self/fd/#{io.fileno}")例

随机推荐