0

I'm trying to create a Grid layout that shows some pictures. Now I'm using a FlowLayout and I create my CollectionView like this:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];


    Gop *g = _images[(NSUInteger) indexPath.row];

    @weakify(self);
    [[self.imageService fetchImageFromURLAsString:g.imageUrl] subscribeNext:^(UIImage *img) {
        @strongify(self);
        UIImageView *imageView = [[UIImageView alloc] initWithImage:img];
        imageView.contentMode = UIViewContentModeScaleAspectFill;
        [cell.contentView addSubview:imageView];
    } error:^(NSError *error) {
        [_snackbar displaySnackbarWithMsg:NSLocalizedString(@"snackbar.error.no.network", nil)];
    } completed:^{
        DDLogDebug(@"Fetched image");
    }];

    return cell;
}

#pragma mark – UICollectionViewDelegateFlowLayout

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    return CGSizeMake(100,100);
}

Don't worry for the reactive cocoa part, it just retrieves an image from the internet.

Now the image is 1920 x 1080 but I want a gallery of images of 100 x 100 for example. So I implemented the UICollectionViewDelegateFlowLayout method and created a size off 100x100. Now my image don't show 100 x 100 and my image content isn't visible. I only see some image from the left corner I guess ( of the bigger picture ).

How can I fit my images that they are 100 x 100 and all in line with each other?

Screenshot what I have now:

enter image description here I hoped on a result something like this: http://www.appcoda.com/wp-content/uploads/2013/01/RecipePhoto-App-First-Version.jpg

user1007522
  • 7,858
  • 17
  • 69
  • 113

2 Answers2

1

Couple of things:

You should not be displaying 1920x1080 images in the UICollectionView, as this will result in really bad performance. Doesn't your web service provide previews?

- (CGSize)collectionView:layout:sizeForItemAtIndexPath: only affects the size of the UICollectionViewCell, it does not resize the images. As you have not provided frame of the UIImageView, it will take the size of its UIImage, which in your case is 1920x1080. Easy fix would be:

//@weakify(self); not necessary, as you are not referencing self inside the blocks
[[self.imageService fetchImageFromURLAsString:g.imageUrl] subscribeNext:^(UIImage *img) {
    //@strongify(self);
    UIImageView *imageView = [[UIImageView alloc] initWithImage:img];
    imageView.frame = cell.bounds; // set the frame of the UIImageView
    imageView.clipsToBounds = YES; // do not display the image outside of view, if it has different aspect ratio
    imageView.contentMode = UIViewContentModeScaleAspectFill;
    [cell.contentView addSubview:imageView];
} error:^(NSError *error) {
    [_snackbar displaySnackbarWithMsg:NSLocalizedString(@"snackbar.error.no.network", nil)];
} completed:^{
    DDLogDebug(@"Fetched image");
}];

Also, think about the cell reuse: if the cell is reused, all of that code will run multiple times, which will result in multiple UIImageViews in the same cell. You can solve this by adding UIImageView to the UICollectionViewCell in the Interface Builder and only accessing it in the code (e.g. via tag):

...
UIImageView *imageView = (UIImageView*)[cell viewWithTag:YOUR_TAG];
...

Also, cell can be potentially reused before the image was loaded from the web service, which will result in multiple images being asynchronously loaded into the same cell, which is quite a mess.

I would suggest to take a look at libraries like AFNetworking or SDWebImage which have already solved this non-trivial problem.

Jakub Vano
  • 3,833
  • 15
  • 29
  • Thanks for the frame = cell.bounds. that solved the problem. Now I'm using AFNetworking to fetch the image. What I don't get is the tag example. Why do I need to make a custom cell? – user1007522 May 05 '15 at 10:53
  • `AFNetworking` provides `UIImageView` methods for asynchronous loading of images, e.g. `-setImageWithURL:placeholderImage:`. You may be over-complicating things here with `ReactiveCocoa`. – Jakub Vano May 05 '15 at 10:56
  • Will take a look. Then the problem is also solved of the reuse of the cells? – user1007522 May 05 '15 at 10:57
  • It doesn't solve the first reuse issue i pointed out: `-dequeueReusableCellWithReuseIdentifier:forIndexPath:` may return the cell, which already has `UIImageView` added from its previous use. One way to solve this is remove old `UIImageView` before adding the new one, but having one created in the interface builder and only referencing it in the code is much simpler. – Jakub Vano May 05 '15 at 11:05
  • Jakub, I now have a custom collectionViewCell with a xib. In the xib there is a ImageView. I set a tag on it and then retrieve the imageview by tag and set the new images. Still got the same problem that you see the previous image when it is recycling.. – user1007522 May 06 '15 at 09:56
  • 1
    Are you using `AFNetworking`s `-setImageWithURL:placeholderImage:`? If you don't specify placeholder image, than previous one will be displayed until new one is loaded. – Jakub Vano May 06 '15 at 10:00
  • If you are still struggling, I would suggest to open new question with updated code – Jakub Vano May 06 '15 at 10:01
0

Add this line to your cell configuration code:

imageView.clipsToBounds = YES
Tiep Vu Van
  • 975
  • 8
  • 13
  • Doesn't change anything. – user1007522 May 05 '15 at 10:19
  • Did you set the Delegate of your collection view? Try using `cell.clipsToBounds = YES` before loading image and make sure it's running in the main thread. – Tiep Vu Van May 05 '15 at 10:20
  • Thanks that solved the problem of the images being separated. Now why is the aspectFill not working? Any idea? – user1007522 May 05 '15 at 10:29
  • As your example, they're using scale to fits. You can see example of AspectFill, AspectFit, ScaleToFill, ScaleToFit in [here](http://img.my.csdn.net/uploads/201211/27/1354011953_1051.png). Also, you should set UIView properties out of block, or make sure they are running on the main thread by `dispatch_async(dispatch_get_main_queue(), ^{ // Your code here })` – Tiep Vu Van May 05 '15 at 10:33
  • I thought that the reactivecocoa block was running on the main queue. – user1007522 May 05 '15 at 10:35