ios 如何创建自定义 UICollectionViewCell 并将图像从 URL 添加到它?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20451578/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 22:40:23  来源:igfitidea点击:

How to create a custom UICollectionViewCell and add image from URL to it?

iosobjective-cuiimageuicollectionviewuicollectionviewcell

提问by KennyVB

i want to load my images i've got from flickr into uicollectionsview i followed allot of guides but they all fall apart when i have to do this

我想将我从 flickr 获得的图像加载到 uicollectionsview 我遵循了很多指南但是当我必须这样做时它们都崩溃了

    cell.imageView.image

it basically says it can't find imageView in object of uicollectionsviewcell

它基本上说它在 uicollectionsviewcell 的对象中找不到 imageView

i also tried a method like this, but it didn't work

我也试过这样的方法,但是没有用

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = @"flickerCell";

UICollectionViewCell *flickerCell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
flickerCell.backgroundColor = [UIColor whiteColor];
UIImageView *recipeImageView = (UIImageView *)[flickerCell viewWithTag:100];
recipeImageView.image = [UIImage imageNamed:[photoURLs objectAtIndex:indexPath.row]];
[flickerCell addSubview:recipeImageView];
return flickerCell;
}

recipieImageView is something i got some a tutorial. my cell is named flickerCell in the storyboard and photoURLs has 33 objects i can view in code . so it's all there. also photoURLs is a NSMutablearray how ever. in this method my recipeImageView returns nill ??? i have a cell.h which has the imageView

recipieImageView 是我得到了一些教程的东西。我的单元格在情节提要中被命名为 flickerCell,而 photoURLs 有 33 个我可以在代码中查看的对象。所以一切都在那里。photoURLs 还是一个 NSMutablearray。在这种方法中,我的 recipeImageView 返回 nill ??? 我有一个带有 imageView 的 cell.h

#import <UIKit/UIKit.h>

@interface Cell : UICollectionViewCell
@property (strong, nonatomic) IBOutlet UIImageView *imageView;

@end

so if anyone know a way i can display all the images that photoURLs has in a uicollectionview it would be very helpful

因此,如果有人知道我可以在 uicollectionview 中显示 photoURLs 的所有图像的方法,那将非常有帮助

UPDATEi now tried a new way but still not working. imageView returns nil

更新我现在尝试了一种新方法,但仍然无法正常工作。imageView 返回 nil

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = @"flickerCell";

Cell *flickerCell = (Cell*) [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];

flickerCell.backgroundColor = [UIColor whiteColor];
imageView.image = [UIImage imageNamed:[photoURLs objectAtIndex:indexPath.row]];
return flickerCell;
}

UPDATE AGAIN

再次更新

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = @"flickerCell";
Cell *flickerCell = (Cell*) [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
NSLog(@"flickercell = %@", flickerCell);
flickerCell.backgroundColor = [UIColor whiteColor];
flickerCell.imageView.image = [UIImage imageNamed:[photoURLs objectAtIndex:indexPath.row]];
return flickerCell;

} with this in viewdidload

在 viewdidload 中使用这个

    [self.collectionView registerClass:[Cell class] forCellWithReuseIdentifier:@"flickerCell"];

NSLOG of flickerCell returns this :

flickerCell 的 NSLOG 返回这个:

    flickercell = <Cell: 0x9dec2f0; baseClass = UICollectionViewCell; frame = (0 0; 120 115); layer = <CALayer: 0x9dec430>>

回答by AXE

As I get it you are using a custom UICollectionViewCell. However in the method you pasted you create a pointer to UICollectionViewCell which has no built-in UIImageView. So that's why you get the error in the first try. About the second - did you register your custom UICollectionViewCell class with the CollectionView?

据我所知,您正在使用自定义 UICollectionViewCell。但是,在您粘贴的方法中,您创建了一个指向 UICollectionViewCell 的指针,该指针没有内置的 UIImageView。所以这就是为什么你在第一次尝试时就会出错。关于第二个 - 您是否使用 CollectionView 注册了您的自定义 UICollectionViewCell 类?

======

======

Edit: after a long chat with the poster we solved all the problems.

编辑:与海报长时间聊天后,我们解决了所有问题。

  • The first one was that the registered class was UICollectionViewCell, not the inherited custom one.
  • The second problem was that the view was actually in a xib file, so registerNib:forCellWithReuseIdentifier:should be used instead of registerClass:forCellWithReuseIdentifier:
  • The third one was that the custom cell was configured in a storyboard xib instead of its own xib file that is wired with the custom class ("Cell" in our case)
  • And fourth main problem was that UIImage was incorrectly created with imageNamed:which should be used only for images that are embedded in the project. The correct way to create the UIImage in our case is: flickerCell.imageView.image = [UIImage imageNamed:[photoURLs objectAtIndex:indexPath.row]];
  • 第一个是注册的类是 UICollectionViewCell,而不是继承的自定义类。
  • 第二个问题是视图实际上是在一个 xib 文件中,所以registerNib:forCellWithReuseIdentifier:应该使用而不是 registerClass:forCellWithReuseIdentifier:
  • 第三个是自定义单元格是在故事板 xib 中配置的,而不是它自己的与自定义类连接的 xib 文件(在我们的例子中是“单元格”)
  • 第四个主要问题是 UIImage 被错误地创建,imageNamed:它应该只用于嵌入到项目中的图像。在我们的例子中创建 UIImage 的正确方法是:flickerCell.imageView.image = [UIImage imageNamed:[photoURLs objectAtIndex:indexPath.row]];

回答by Bhumeshwer katre

It may help you.

它可能会帮助你。

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
        static NSString *identifier = @"flickerCell";

        Cell *flickerCell = (Cell*) [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];

        flickerCell.backgroundColor = [UIColor whiteColor];
        flickerCell.imageView.image = [UIImage imageNamed:[photoURLs objectAtIndex:indexPath.row]];
        return flickerCell;
}

回答by Vignesh Kumar

You can easily create a custom UICollectionViewCell class with custom the animation while tap the UICollectionViewCell. So, You don't need to add any specific method/action for the animation.

您可以在点击 UICollectionViewCell 时轻松创建自定义动画的自定义 UICollectionViewCell 类。因此,您不需要为动画添加任何特定的方法/动作。

  • In storyboard - Add a UICollectionViewCell with cell identifier, UIImageView and UILabel.
  • Assign both UIImageView and UILabel property to Storyboard cell.
  • Import the 'UviCollectionCell.h' in your view controller.

    In YourViewController.h

    - (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    
        UviCollectionCell *cell = (UviCollectionCell *)  [cv dequeueReusableCellWithReuseIdentifier:@"collection_cell" forIndexPath:indexPath];
        [cell.cellImageView setBackgroundColor: [UIColor randomColor]];
        // You can add your image here.
        cell.cellImageView.image = [UIImage imageNamed:[photoURLs objectAtIndex:indexPath.row]];
        [cell.cellTitle setText:[NSString stringWithFormat:@"S %ld - R %ld",(long)indexPath.section,(long)indexPath.row]];
    
        //cell.backgroundColor = [UIColor randomColor];
        return cell;
    }  
    

    UviCollectionCell.h

        #import <UIKit/UIKit.h>
    
        @interface UviCollectionCell : UICollectionViewCell<UIGestureRecognizerDelegate>
    
        @property (strong, nonatomic) IBOutlet UIImageView *cellImageView;
        @property (strong, nonatomic) IBOutlet UILabel *cellTitle;
    
        @end
    

    UviCollectionCell.m

        #import "UviCollectionCell.h"
    
        @implementation UviCollectionCell
    
        // Initialize the collectiion cell based on the frame and add the tap gesture recognizer for custom animation
        - (id)initWithFrame:(CGRect)frame {
            self = [super initWithFrame:frame];
    
            // Custom animation while tap the CollectionCell view.
            UITapGestureRecognizer *tapReconizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(selectedCellAnimation)];
            [tapReconizer setNumberOfTouchesRequired : 1];
            [tapReconizer setDelegate:self];
            [self addGestureRecognizer:tapReconizer];
    
            return self;
        }
    
        // Initialize the collection cell based on the nscoder and add the tap gesture recognizer for custom animation
        -(id) initWithCoder:(NSCoder *)aDecoder {
             self = [super initWithCoder:aDecoder];
            // Custom animation while tap the CollectionCell view.
            UITapGestureRecognizer *tapReconizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(selectedCellAnimation)];
            [tapReconizer setNumberOfTouchesRequired : 1];
            [tapReconizer setDelegate:self];
            [self addGestureRecognizer:tapReconizer];
    
             return self;
        }
    
        // Initialize the collectiion cell and add the tap gesture recognizer for custom animation
        -(id) init {
            self = [super init];
    
            // Custom animation while tap the CollectionCell view.
            UITapGestureRecognizer *tapReconizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(selectedCellAnimation)];
            [tapReconizer setNumberOfTouchesRequired : 1];
            [tapReconizer setDelegate:self];
            [self addGestureRecognizer:tapReconizer];
    
            return self;
        }
    
        // Customize the animation while tap the UICollectionViewCell with custom animation duration.
        - (void)selectedCellAnimation {
            [UIView animateWithDuration:0.4 delay:0 options:(UIViewAnimationOptionCurveEaseIn) animations:^{
                CALayer *layer = self.layer;
                CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
                rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, 25.0f * M_PI / 180.0f, 1.0f, 0.0f, 0.0f);
                layer.transform = rotationAndPerspectiveTransform;
            } completion:^(BOOL finished) {
                [UIView animateWithDuration:0.3 delay:0 options:(UIViewAnimationOptionCurveEaseOut) animations:^{
                    CALayer *layer = self.layer;
                    CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
                    rotationAndPerspectiveTransform.m24 = 0;
                    rotationAndPerspectiveTransform =CATransform3DRotate(rotationAndPerspectiveTransform, 0.0f * M_PI / 180.0f, 1.0f, 0.0f, 0.0f);
                    layer.transform = rotationAndPerspectiveTransform;
                } completion:nil];
            }];
        }
    
        @end
    
  • 在故事板中 - 添加带有单元标识符、UIImageView 和 UILabel 的 UICollectionViewCell。
  • 将 UIImageView 和 UILabel 属性分配给 Storyboard 单元格。
  • 在您的视图控制器中导入“UviCollectionCell.h”。

    在 YourViewController.h 中

    - (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    
        UviCollectionCell *cell = (UviCollectionCell *)  [cv dequeueReusableCellWithReuseIdentifier:@"collection_cell" forIndexPath:indexPath];
        [cell.cellImageView setBackgroundColor: [UIColor randomColor]];
        // You can add your image here.
        cell.cellImageView.image = [UIImage imageNamed:[photoURLs objectAtIndex:indexPath.row]];
        [cell.cellTitle setText:[NSString stringWithFormat:@"S %ld - R %ld",(long)indexPath.section,(long)indexPath.row]];
    
        //cell.backgroundColor = [UIColor randomColor];
        return cell;
    }  
    

    UviCollectionCell.h

        #import <UIKit/UIKit.h>
    
        @interface UviCollectionCell : UICollectionViewCell<UIGestureRecognizerDelegate>
    
        @property (strong, nonatomic) IBOutlet UIImageView *cellImageView;
        @property (strong, nonatomic) IBOutlet UILabel *cellTitle;
    
        @end
    

    UviCollectionCell.m

        #import "UviCollectionCell.h"
    
        @implementation UviCollectionCell
    
        // Initialize the collectiion cell based on the frame and add the tap gesture recognizer for custom animation
        - (id)initWithFrame:(CGRect)frame {
            self = [super initWithFrame:frame];
    
            // Custom animation while tap the CollectionCell view.
            UITapGestureRecognizer *tapReconizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(selectedCellAnimation)];
            [tapReconizer setNumberOfTouchesRequired : 1];
            [tapReconizer setDelegate:self];
            [self addGestureRecognizer:tapReconizer];
    
            return self;
        }
    
        // Initialize the collection cell based on the nscoder and add the tap gesture recognizer for custom animation
        -(id) initWithCoder:(NSCoder *)aDecoder {
             self = [super initWithCoder:aDecoder];
            // Custom animation while tap the CollectionCell view.
            UITapGestureRecognizer *tapReconizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(selectedCellAnimation)];
            [tapReconizer setNumberOfTouchesRequired : 1];
            [tapReconizer setDelegate:self];
            [self addGestureRecognizer:tapReconizer];
    
             return self;
        }
    
        // Initialize the collectiion cell and add the tap gesture recognizer for custom animation
        -(id) init {
            self = [super init];
    
            // Custom animation while tap the CollectionCell view.
            UITapGestureRecognizer *tapReconizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(selectedCellAnimation)];
            [tapReconizer setNumberOfTouchesRequired : 1];
            [tapReconizer setDelegate:self];
            [self addGestureRecognizer:tapReconizer];
    
            return self;
        }
    
        // Customize the animation while tap the UICollectionViewCell with custom animation duration.
        - (void)selectedCellAnimation {
            [UIView animateWithDuration:0.4 delay:0 options:(UIViewAnimationOptionCurveEaseIn) animations:^{
                CALayer *layer = self.layer;
                CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
                rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, 25.0f * M_PI / 180.0f, 1.0f, 0.0f, 0.0f);
                layer.transform = rotationAndPerspectiveTransform;
            } completion:^(BOOL finished) {
                [UIView animateWithDuration:0.3 delay:0 options:(UIViewAnimationOptionCurveEaseOut) animations:^{
                    CALayer *layer = self.layer;
                    CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
                    rotationAndPerspectiveTransform.m24 = 0;
                    rotationAndPerspectiveTransform =CATransform3DRotate(rotationAndPerspectiveTransform, 0.0f * M_PI / 180.0f, 1.0f, 0.0f, 0.0f);
                    layer.transform = rotationAndPerspectiveTransform;
                } completion:nil];
            }];
        }
    
        @end
    

回答by CouchDeveloper

In your code

在你的代码中

imageView.image = [UIImage imageNamed:[photoURLs objectAtIndex:indexPath.row]];

what does [photoURLs objectAtIndex:indexPath.row]return?

哪些呢[photoURLs objectAtIndex:indexPath.row]回报呢?

For use with imageNamed:it MUST return a NSStringobject which is the name of a resource located in the main bundle. It won't work with a URL, even less if this URL is pointing to a remote URL.

imageNamed:它一起使用必须返回一个NSString对象,它是位于主包中的资源的名称。它不适用于 URL,如果此 URL 指向远程 URL,则更是如此。

Anyway, you shouldn't use imageNamed. This method caches the image in the system's cache, which is not optimal/required in a collection/table view. Instead use an alternative method to create the UIImageobject.

无论如何,你不应该使用imageNamed. 此方法将图像缓存在系统缓存中,这在集合/表视图中不是最佳/必需的。而是使用替代方法来创建UIImage对象。

A solution to your problem depends whether you need to load your image data from a remote server or if these resources are located on the device.

问题的解决方案取决于您是否需要从远程服务器加载图像数据,或者这些资源是否位于设备上。

In the first case, you need an asynchronous approach in conjunction with a "placeholder image" which represents an image while being loaded when it is displayed in the cell.

在第一种情况下,您需要一种与“占位符图像”结合的异步方法,该“占位符图像”表示在单元格中显示时加载时的图像。

In the second case, you may use a simple synchronous approach to load images (similar to your existing solution, but using imageWithContentsOfFile:for example), unless the images are large, in which case you need an asynchronous approach too.

在第二种情况下,您可以使用简单的同步方法来加载图像(类似于您现有的解决方案,但imageWithContentsOfFile:例如使用),除非图像很大,在这种情况下您也需要异步方法。

Note: your code has a few other issues, too - but first and foremost you need to tell where your images come from.

注意:您的代码也有一些其他问题 - 但首先您需要知道您的图像来自哪里。

A possible (but not optimal) solution for loading images from the diskon the device:

设备上的磁盘加载图像的可能(但不是最佳)解决方案:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
                  cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *identifier = @"flickerCell";
    FlickerCell* flickerCell = (FlickerCell*) [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
    flickerCell.backgroundColor = [UIColor whiteColor];
    NSURL* url = [self.photoURLs objectAtIndex:indexPath.row]; // file URL
    flickerCell.imageView.image = [UIImage imageWithContentsOfFile:[url path]];
    return flickerCell;
}

A more sophisticated solution would loadand decodeimages aheadin a background thread - before they are actually displayed. That way, whenthey are actually displayed, the images are possibly already encoded and will render much faster. This also requires a cache.

更复杂的解决方案是在后台线程中提前加载解码图像- 在它们实际显示之前。这样,它们实际显示时,图像可能已经被编码并且渲染速度会快得多。这也需要缓存。