Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS

How to add a button to a PhotoCell

Basically i have a collectionView and a custom cell in which i want to put a button that can be tapped to like the picture but i don't want to put the button code in the photo cell in order to keep it as simple as possible. How would i put the code for the button in my main viewController in cellForItemAtIndexPath i guess?

thanks!

6 Answers

I'll just provide an example here based on the photo browsing app here on treehouse:

In you PhotoCell.h file you create a protocol:

@class PhotoCell;

@protocol PhotoCellDelegate <NSObject>
- (void)didPressButtinInImageView:(PhotoCell *)photoCell;
@end

@interface PhotoCell : UICollectionViewCell

@property (nonatomic) UIImageView *imageView;
@property (nonatomic) NSDictionary *photo;
@property (nonatomic, weak) id <PhotoCellDelegate> delegate;
@end

in the m.file you make a button, add it as a subview, and add a target (to receive touch)

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Alloc and add the imageview, set an image to the imageview
        self.imageView = [[UIImageView alloc] init];
        //self.imageView.image = [UIImage imageNamed:@"Treehouse"];
        UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
        [button setFrame:CGRectMake(0, 0, 40, 40)];
        [button addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
        UITapGestureRecognizer *tab = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(like)];
        tab.numberOfTapsRequired = 2;
        [self addGestureRecognizer:tab];

        [self.contentView addSubview:self.imageView];
        [self.contentView addSubview:button];

    }
    return self;
}

- (void)buttonPressed:(UIButton *)sender
{
    [_delegate didPressButtinInImageView:self];
}

Now all you have to do is implement the new custom delegate protocol we've just made in our viewController. A few things are required:

@interface PhotosViewController () <UIViewControllerTransitioningDelegate, PhotoCellDelegate> //add the protocol here
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    PhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"photo" forIndexPath:indexPath];

    cell.backgroundColor = [UIColor lightGrayColor];
    cell.photo = self.photos[indexPath.row];
    cell.delegate = self; // set the delegate for every cell in our collectionView

    return cell;
}

and finally do something in our method:

- (void)didPressButtinInImageView:(PhotoCell *)photoCell
{
    NSIndexPath *indexPath = [self.collectionView indexPathForCell:photoCell];
    NSLog(@"This photo was taken by: %@", self.photos[indexPath.row][@"caption"][@"from"][@"full_name"]);
}

Hope this helps :)

You have said so yourself, you could just implement a method that handles everything inside you PhotoCell.m instead of delegation. Maybe Amit Bijlani has some input on what the best course of action would be

Thats brilliant thanks Thomas i shall give this a try, thanks a million!

Also Thomas, wondered how i would then access my button in the cell from that method to change the image when it changes to UIControlStateSelected for example.

I know that i would need this code:

[cell.likeButton setImage:[UIImage imageNamed:@"redstar"] forState:UIControlStateSelected];

but because i'm not in cellForItem and in the method i can no longer access the cell and the button property i've set.

Thanks in advance!

I don't understand what you mean by keeping it as simple as possible. Putting the UIbutton code in the custom cell implementation is actually what you should do :). But, if you want to do that in cellForItemAtIndexPath, it would look something like this (this is based on custom cell in a tableView, but the concept is still the same)

TNSwipeableCell *cell = (TNSwipeableCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (!cell) {
        cell = [[TNSwipeableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
    UIButton *test = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
    [test setFrame:CGRectMake(20, 140, 50, 50)]; 
    [cell insertSubview:test aboveSubview:cell.topLayerView]; //topLayerView is the topmost view in my custom cell, the button is placed       above it

   return cell;

Thanks for the response, but what i meant was the button logic. I have a button in my PhotoCell that i want to, when pressed, like the photo. I've got the logic for this but unsure as to where to put it in CellForItem

You could use a delegation pattern. If you're unsure of what I mean by this, then say so and I'll provide an example :) Or send me your code and I can implement it for you, and I'll send it back ;)

Thanks Thomas! That would be great if you could give me an example/ explain that. Still learning! haha

Do you mind sending me the code through a dropbox link or something? It's faster for me to just implement it there so you can have a look :)

what parts do you need?

you can just zip the entire project ;)

I've put the parts on paste bin for now if thats okay! http://pastebin.com/jXcS8uLc

If you use the delegation pattern you should be able to access the cell properties. The method we made:

- (void)didPressButtinInImageView:(PhotoCell *)photoCell
{
    NSIndexPath *indexPath = [self.collectionView indexPathForCell:photoCell];
    NSLog(@"This photo was taken by: %@", self.photos[indexPath.row][@"caption"][@"from"][@"full_name"]);
}

this method has a referenece to whatever cell was tapped (photoCell) and you can it's properties here.