Issues refreshing UITableView Cell UI Button Images from Delegate Method - ios

I am having an issue correctly setting the image for UIButtons in a UITableViewCell. I am using a custom Cell in Storyboard with Four buttons to create a Gallery effect and loading the images from a server using an ImageLoader Delegate like in Apple's LazyTableImages' sample code. I am getting the images back from the ImageLoader just fine, the problem is setting the image.
If I set the images in the UITableView cellForRowAtIndexPath, I can set the images fine if they are already loaded or just default images:
for (int i = 0; i < [posts count] && i < [galleryButtons count]; i++)
{
post = [posts objectAtIndex:i];
UIButton *button = [galleryButtons objectAtIndex:i];
[button setTag:post.userID];
if (!post.userIcon)
{
if (tableView.dragging == NO && tableView.decelerating == NO)
{
loadFlag = YES;
}
[button setImage:[UIImage imageNamed:#"BtDefault.png"] forState:UIControlStateNormal];
} else
{
[button setImage:post.userIcon forState:UIControlStateNormal];
}
}
if (loadFlag)
{
[self startIconDownload:posts forIndexPath: indexPath];
}
However when the delegate calls the ImageDidLoad method later on, the images are not changing.
- (void)postImageDidLoad:(NSIndexPath *)indexPath forColumn:(int)postColumn
{
ImageLoader *imageLoader = [imageDownloadsInProgress objectForKey:indexPath];
Post *post;
if (imageLoader != nil)
{
UITableViewCell *cell = [timeLineTable cellForRowAtIndexPath:indexPath];
if (timeLineStyle == 1) //Gallary Style
{
int index = (indexPath.row * 4) + postColumn;
int buttonTag = 200 + postColumn + 1;
NSLog(#"Button tag is %i", buttonTag);
post = [currentPosts objectAtIndex:index];
UIButton *galleryButton = (UIButton *)[cell viewWithTag:buttonTag];
[galleryButton setImage:post.userIcon forState:UIControlStateNormal];
UIImageView *imageTester = (UIImageView *)[cell viewWithTag:300];
[imageTester setImage:post.userIcon];
[timeLineTable reloadData];
[cell setHighlighted:YES];
} else // Post Style
{
UIImageView *userImageView = (UIImageView*)[cell viewWithTag:101];
UILabel *userNameLabel = (UILabel *)[cell viewWithTag:102];
[userNameLabel setText:#"Image Loaded"];
post = [currentPosts objectAtIndex:[indexPath row]];
[userImageView setImage:post.userIcon];
}
}
}
You can see I have a UIImage in the cell for testing. This is working just fine. This code also works fine if I remove the for loop in the cellForRowAtIndexPath up above. The problem is without that for loop, the button images are not set if the images are already loaded.
I'm not sure if this is a problem with too many pointers preventing the UIButton from changing. That is all I can think of, but I am pretty new with StoryBoard and this style of Custom Cell manipulation. Thanks for any help.

Up top you set the button tag as [button setTag:post.userID]; but down the bottom you retrieve the button using the tag: int buttonTag = 200 + postColumn + 1;

Related

Odd behaviour with UITableViewCell when scrolling, UIButtons disappearing

I am trying to set up some UIButtons and UILabels in my custom UITableViewCell. For each row in the table I have 4 buttons with user profile images and below each button is a label displaying the username. Images and usernames are taken from Parse.com. I have a friends array of size 34, and I am displaying 9 rows so the last two buttons and label must be hidden. The code below works but for some reason when I scroll up the table some of the other rows will also hide their two rightmost buttons and labels. I'm wondering if my logic for loading images from the array is incorrect. Not sure what's going on here. Any advice would be greatly appreciated.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
FriendViewCell *cell = (FriendViewCell *)[tableView dequeueReusableCellWithIdentifier:#"friendCell" forIndexPath:indexPath];
for (int i = 0; i < 4; i++) {
if ((int)indexPath.row * 4 + i < [self.currentUser.friends count]) {
UIButton *button = cell.buttons[i];
[button setTag:(int)indexPath.row * 4 + i];
button.layer.cornerRadius = button.frame.size.width / 2;
button.clipsToBounds = YES;
UILabel *label = cell.labels[i];
[button addTarget:self action:#selector(friendTapped:) forControlEvents:UIControlEventTouchUpInside];
//here we need to decide what to access
PFUser *user = self.currentUser.friends[(int)indexPath.row * 4 + i];
label.text = user.username;
PFFile *userImageFile = user[#"profilePic"];
[userImageFile getDataInBackgroundWithBlock: ^(NSData *imageData, NSError *error) {
if (!error) {
UIImage *image = [UIImage imageWithData:imageData];
[button setBackgroundImage:image forState:UIControlStateNormal];
}
}];
}
else {
UIButton *button = cell.buttons[i];
[button setEnabled:NO];
[button setHidden:YES];
UILabel *label = cell.labels[i];
[label setHidden:YES];
}
}
return cell;
}
You can try by unhiding the button and Label in your first conduction like:
if ((int)indexPath.row * 4 + i < [self.currentUser.friends count]) {
[button setEnabled:YES];
[button setHidden:NO];
[label setHidden:NO];
// Other code
}
else{
......
}
The 'iOS' way to handle this would be to fill out the prepareForReuse method of your custom cell. This is where you should be reseting various attributes on cells that may be reused by the caching system.
Apple Docs
-prepareForReuse
Prepares a reusable cell for reuse by the table view's delegate.
Discussion
If a UITableViewCell object is reusable—that is, it has a reuse identifier—this method is invoked just before the object is returned from the UITableView method dequeueReusableCellWithIdentifier:. For performance reasons, you should only reset attributes of the cell that are not related to content, for example, alpha, editing, and selection state. The table view's delegate in tableView:cellForRowAtIndexPath: should always reset all content when reusing a cell. If the cell object does not have an associated reuse identifier, this method is not called. If you override this method, you must be sure to invoke the superclass implementation.

Adding UIButtons to uiimage of a UICollectionView cells programmatically

I have a UIViewController with a UICollectionView image gallery created inside it programmatically. I want to add a button to the on each uiimage of UICollectionView cell: The code in CMFViewController.h.m file for adding button to imageview is:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
CMFGalleryCell *cell = (CMFGalleryCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
NSString *imageName = [self.dataArray objectAtIndex:indexPath.row];
[cell setImageName:imageName];
// [[cell myButton] addTarget:self action:#selector(myClickEvent:event) forControlEvents:UIControlEventTouchUpInside];
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(80.0, 210.0, 100.0, 20.0);
[button addTarget:self action:#selector(show) forControlEvents:UIControlEventTouchUpInside];
[button setTitle:#"ShowView" forState:UIControlStateNormal];
// NSMutableArray *buttonArray = [NSMutableArray arrayWithCapacity:100];
// for (int i = 0; i < 4; i++) {
// NSUInteger index = arc4random() % 4;
// newButton.frame = CGRectMake( 5, 5, 10, 10); // Whatever position and size you need...
// UIImage *buttonImage = [UIImage imageNamed:[self.dataArray objectAtIndex:indexPath.row]];
//[newButton setBackgroundImage:buttonImage forState:UIControlStateNormal];
// [buttonArray addObject:newButton];
// }
// newButton = buttonArray; // Where myButtons is a NSArray property of your class, to store references to the buttons.
// [newButton addTarget:self action:#selector(loadImages:) forControlEvents:UIControlEventTouchUpInside];
//[newButton addTarget:self action:#selector(updateCell) forControlEvents:UIControlEventTouchUpInside];
[cell updateCell];
return cell;
}
I have tied to get help from codes at following links
adding-a-uibutton-to-a-uicollectionview
UIButton in cell in collection view not receiving touch up inside event
Please give my your suggestion and help me on this issue.
from this link u can download source code in Creating a Paged Photo Gallery With a UICollectionView: their i want to place next and previous buttons on middle lines of each image of the screen
For implementing next and previous buttons, don't added it on each image, better u add it on collection view, what chinttu-maddy-ramani told in his answer is correct, but he is doing in xib file, but programatically u can do it like below,
just add this code
Edit for requirement updating the buttons
in CMFViewController.h file make two button properties
replace by below code
#import <UIKit/UIKit.h>
#interface CMFViewController : UIViewController <UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>
#property (nonatomic, strong) UIButton *nextButton;
#property (nonatomic, strong) UIButton *prevButton;
#end
in CMFViewController.m file
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self loadImages];
[self setupCollectionView];
[self addNextAndPreviousButtons];//add a method to add previous and next buttons
}
//hear u are adding previous and next images, but i didn't added the constraints u add it if u want t work in both orientation
- (void)addNextAndPreviousButtons
{
_nextButton = [UIButton buttonWithType:UIButtonTypeSystem];
_nextButton.frame =CGRectMake(self.view.bounds.size.width - 40, self.view.bounds.size.height/2, 50, 30);
[_nextButton setTitle:#"Next" forState:UIControlStateNormal];
[_nextButton addTarget:self action:#selector(nextButtonAction:) forControlEvents:UIControlEventTouchUpInside];
_prevButton = [UIButton buttonWithType:UIButtonTypeSystem];
_prevButton.frame = CGRectMake(self.view.bounds.origin.x, self.view.bounds.size.height/2, 50, 30);
[_prevButton setTitle:#"Prev" forState:UIControlStateNormal];
[_prevButton addTarget:self action:#selector(previousButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_nextButton];
[self.view addSubview:_prevButton];
}
//previous button action
- (void)previousButtonAction:(id)sender
{
NSArray *visibleCell = [_collectionView visibleCells];
if(visibleCell)
{
NSIndexPath *path = [_collectionView indexPathForCell:[visibleCell lastObject]];
if(!path.row == 0)
{
NSIndexPath *nextPath = [NSIndexPath indexPathForItem:(path.row - 1) inSection:0];
[_collectionView scrollToItemAtIndexPath:nextPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];
}
}
}
//next button action
- (void)nextButtonAction:(id)sender
{
NSArray *visibleCell = [_collectionView visibleCells];
if(visibleCell)
{
NSIndexPath *path = [_collectionView indexPathForCell:[visibleCell lastObject]];
if(path.row < [_dataArray count] - 1)
{
NSIndexPath *nextPath = [NSIndexPath indexPathForItem:(path.row + 1) inSection:0];
[_collectionView scrollToItemAtIndexPath:nextPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];
}
}
}
//edited the method addNextAndPreviousButtons please replace it by this edited answer
//for all cases even when u are swiping
//this is to handle buttons either by tapping or navigation through swiping the collection view
- (void)updateButtons:(NSInteger)row
{
//at the beginning
if(row == 0)
{
_prevButton.hidden = YES;
_nextButton.hidden = NO;
return;
}
else if(row == ([_dataArray count] -1))
{
_nextButton.hidden = YES;
_prevButton.hidden = NO;
}
else
{
_nextButton.hidden = NO;
_prevButton.hidden = NO;
}
}
//finally u have to call updateButtons method this method
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CMFGalleryCell *cell = (CMFGalleryCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
NSString *imageName = [self.dataArray objectAtIndex:indexPath.row];
[cell setImageName:imageName];
[cell updateCell];
[self updateButtons:indexPath.row]; //update the buttons
return cell;
}
you can add button in you cell to direct drag & drop button in CMFGalleryCell.xib please check attach screenshot. and add button constraint to center horizontally and center vertically with your cell.
for suggestion only if you want next-previous functionality then you can also add button in main xib in CMFViewController.xib as per below screenshot.

uitableview cells display wrong data when off screen at loading time

I have a UITableView that exceeds the screen region. I display some data from an NSMutableArray which is filled with NSDictionary objects. The objects all have a group property which is true or false, if group is true a UIButton should be displayed in the cell (to expand the group).
I created a UIButton in my cell prototype in storyboard. I gave it alpha 0. If I load the list the button is not in any cell (duh). This is in my cellForRowAtIndexPath:
if ([[contacts[indexPath.section] valueForKey:#"group"] isEqualToString:#"true"]) {
UIButton *button = (UIButton*)[cell viewWithTag:999];
[button setAlpha:1.0f];
}
If the group property is true make the button visible. In my current test case the first three objects have group set to true, the rest have group set to false. Now my problem is, the first three cells have a visible button (as intended), but some cells further along the table have one as well. I put a breakpoint in the above if statement, and it really goes in there only three times.
It happens in a pattern, the first three cells have a button, than five cells don't and than another three have a visible button. Than another five have no button and the last cell does (I think if I add two cells they will also have a button)
The second group of cells that have a button starts just outside the screen, so that may have something to do with it.
One more relevant thing, There is also some text displayed that I take from the same array as the group flag, this text is displayed correct. So it's not that the cells are duplicated somehow, it's just the if statement part that screws up.
I double checked the amount of times the program goes into the if statement and it's really only three times (the first three entries). If I comment the setAlpha call on the button no buttons appear anywhere, so there is also no other place where the button can become visible.
I'm testing on an iPad 4 with iOS 7.1.
If I decrease the height of my rows so all of them fit in the screen, the problem is gone, so It's definitely related to rows falling outside the screen region while loading the data.
edit
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
UIColor *color = [UIColor colorWithRed:(1.0f/255.0f)*220 green:(1.0f/255.0f)*220 blue:(1.0f/255.0f)*225 alpha:1.0f];
if (indexPath.row == 0) {
cell = [tableView dequeueReusableCellWithIdentifier:#"single" forIndexPath:indexPath];
UILabel *screenname = (UILabel*)[cell viewWithTag:10];
UILabel *username = (UILabel*)[cell viewWithTag:11];
UIImageView *avatar = (UIImageView*)[cell viewWithTag:20];
if ([[contacts[indexPath.section] valueForKey:#"group"] isEqualToString:#"true"]) {
NSDictionary *c = contacts[indexPath.section];
UIButton *button = (UIButton*)[cell viewWithTag:999];
[button setAlpha:1.0f];
button.tag = indexPath.section;
[button addTarget:self action:#selector(onGroupButtonClick:) forControlEvents:UIControlEventTouchUpInside];
int numUsersInGroup = [[c valueForKey:#"users"] count];
NSString *numUsersInGroupString = [NSString stringWithFormat:#"%d",numUsersInGroup];
[button setTitle:numUsersInGroupString forState:0];
[button setNeedsDisplay];
screenname.text = #"Groep";
username.text = [NSString stringWithFormat:#"%#",[c valueForKey:#"groupName"]];
} else {
User *c = (User*)contacts[indexPath.section];
UIButton *button = (UIButton*)[cell viewWithTag:999];
[button setAlpha:0.0f];
screenname.text = [NSString stringWithFormat:#"%#",[c valueForKey:#"screenName"]];
username.text = [NSString stringWithFormat:#"%#",[c valueForKey:#"username"]];
[avatar setImage:[UIImage imageNamed:#"avatar.png"]];
}
[GeneralFunctions setFontFamily:#"KozGoPro-ExtraLight" forView:cell andSubViews:YES];
[GeneralFunctions setFontFamily:#"KozGoPro-Medium" forView:screenname andSubViews:YES];
[cell.layer setShadowColor:[color CGColor]];
[cell.layer setShadowOffset:CGSizeMake(0,4)];
[cell.layer setShadowRadius:3.0f];
[cell.layer setShadowOpacity:1.0f];
cell.clipsToBounds = NO;
cell.layer.masksToBounds = NO;
}
if (indexPath.row > 0) {
cell = [tableView dequeueReusableCellWithIdentifier:#"group" forIndexPath:indexPath];
UILabel *screenname = (UILabel*)[cell viewWithTag:10];
UILabel *username = (UILabel*)[cell viewWithTag:11];
User *c = (User*)[contacts[indexPath.section] valueForKey:#"users"][indexPath.row-1];
screenname.text = [NSString stringWithFormat:#"%#",[c valueForKey:#"screenName"]];
username.text = [NSString stringWithFormat:#"%#",[c valueForKey:#"username"]];
[GeneralFunctions setFontFamily:#"KozGoPro-ExtraLight" forView:cell andSubViews:YES];
[GeneralFunctions setFontFamily:#"KozGoPro-Medium" forView:screenname andSubViews:YES];
}
return cell;
}
When your cell is reused you are not setting the button back to the 0.0 alpha. You need to reset your cell or change your cell's property whenever you reuse a cell otherwise it'll show the old content
if ([[contacts[indexPath.section] valueForKey:#"group"] isEqualToString:#"true"]) {
NSDictionary *c = contacts[indexPath.section];
UIButton *button = (UIButton*)[cell viewWithTag:999];
[button setAlpha:1.0f];
//this line changes your tag and hence in else condition for reused cell it'll come nil
button.tag = indexPath.section;
} else {
UIButton *button = (UIButton*)[cell viewWithTag:999];
[button setAlpha:0.0f];
}
Suggestion instead of accessing button by tag access it by using property by type casting the cell into your custom cell

Remove a button from a custom UITableViewCell after deleting the data from it

I have a custom UITableViewCell that also holds a custom UIButton as a subview. The button shows another image, dependent on the UITableViewCell.textLabel.text-data.
When I now remove a row the data gets deleted and moves one up. The problem there is, that the image stays. So, the images are overlaying now. See here
The image should be either blue or red, not both. Also you can see, that it is a bit thicker. That's because the row gets deleted and the data it contains ( and in the array ) but not the image. I'm using a custom UITableViewCell to have a custom swipe to delete. The swipe gesture also lets the user edit data. Not only delete it.
This is the method that gets called, when I press either the delete or edit button
- (void)swipeableTableViewCell:(SWTableViewCell *)cell didTriggerRightUtilityButtonWithIndex:(NSInteger)index {
switch (index) {
case 0: {
//stuff for editing
}
case 1:{
NSString *stringIdentifierTemp = cell.projectCellIdentifier;
Firebase *firebaseReferenceTemp = [[Firebase alloc] initWithUrl:[NSString stringWithFormat:#"%#/%#", stringRequestUrl, stringIdentifierTemp]];
if ( self.boolFirstTableView ){
[dictionaryProjects removeObjectForKey:stringIdentifierTemp];
[firebaseReferenceTemp updateChildValues:#{#"state": #"canceled"}];
} else {
[dictionaryFinishedProjects removeObjectForKey:stringIdentifierTemp];
[firebaseReferenceTemp removeValue];
}
[tableView reloadData];
[tableViewFinished reloadData];
break;
}
default:
break;
}
}
As you can see I remove the data from the NSMutableDictionary that holds the data and then reload the tableviews I have. Still, the images are overlaying.
In the method - (SWTableViewCell *)tableView:(UITableView *)realTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath, where I define the UITableViewCells this is how I add the button
CustomButton *stateButton = [CustomButton buttonWithType:UIButtonTypeRoundedRect];
stateButton.projectButtonIdentifier = tempIdentifier;
stateButton.frame = CGRectMake(5.0f, 5.0f, 44.0f, 44.0f);
[stateButton setContentVerticalAlignment:UIControlContentVerticalAlignmentCenter];
[stateButton setContentHorizontalAlignment:UIControlContentHorizontalAlignmentCenter];
[stateButton addTarget:self action:#selector(updateState:) forControlEvents:UIControlEventTouchUpInside];
Firebase *tempRef = [[Firebase alloc] initWithUrl:[NSString stringWithFormat:#"%#/%#", stringRequestUrl, tempIdentifier]];
[tempRef observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) {
if ( [snapshot.name isEqualToString:#"state"] ) {
if ( [snapshot.value isEqualToString:#"new"]){
if ( [important isEqualToString:#"No"] ){
[stateButton setBackgroundImage:imageStatusNew forState:UIControlStateNormal];
} else {
[stateButton setBackgroundImage:imageStatusNewRed forState:UIControlStateNormal];
}
} else if ( [snapshot.value isEqualToString:#"started"]){
if ( [important isEqualToString:#"No"] ){
[stateButton setBackgroundImage:imageStatusStarted forState:UIControlStateNormal];
} else {
[stateButton setBackgroundImage:imageStatusStartedRed forState:UIControlStateNormal];
}
} else if ( [snapshot.value isEqualToString:#"halfway"]){
if ( [important isEqualToString:#"No"] ){
[stateButton setBackgroundImage:imageStatusHalfway forState:UIControlStateNormal];
} else {
[stateButton setBackgroundImage:imageStatusHalfwayRed forState:UIControlStateNormal];
}
}
}
}];
[cell addSubview:stateButton];
A simple off topic: I know it should be written cancelled but I didn't make these. :p
Seems like the problem was, that I was always using the same CellIdentifier. Now I just set it to nil and it worked.
SWTableViewCell *cell = (SWTableViewCell *)[realTableView dequeueReusableCellWithIdentifier:nil];
// Cell
if ( cell == nil ){
cell = [[SWTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:nil
containingTableView:realTableView leftUtilityButtons:[self leftButtons] rightUtilityButtons:[self rightButtons]];
cell.delegate = self;
}
When you use a cell identifier, cells that are no longer visible get reused to save memory, so the cell returned when dequeueing may have a button already.
In your tableView:cellForRowAtIndexPath: you should remove the button if the cell already has one, you can do this by setting a tag for it:
CustomButton *stateButton = ...
...
stateButton.tag = 12345; // use a tag to identify the button
[[cell viewWithTag:stateButton.tag] removeFromSuperview]; // removes old button if it exists
[cell addSubview:stateButton];
instead of deleting the data from from the cell you can delete the whole row.

Button Image Quality Collection View

I have a collection view where each cell contains 7 buttons, (created via code not storyboard).
They are sharp initially, however if I scroll up / down a few times the quality decreases.
The sharpness is restored when I change views and return.
Any ideas ?
Addit:
I am making the buttons like this, within a loop (can be 1 to 7 buttons)
- (UICollectionViewCell*) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"patientCell";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
Patient *aPt = [self.fetchedResultsController objectAtIndexPath:indexPath];
PatientCVCell *ptCell = (PatientCVCell *) cell;
ptCell.ptName.text = aPt.name;
ptCell.ptRoom.text = aPt.room;
ptCell.ptRx.text = aPt.diagnosis;
int xPos = 20;
NSArray *daysForRx = aPt.ofList.listDays;
// loop through to add button for each day of Rx
for (int i = 0; i < [daysForRx count]; i++) {
// get the treatment day that == postition in array
for (Treatment *t in aPt.patientRx) {
if (t.day == daysForRx[i]) {
//NSLog(#"%i", xPos);
StatusButton *testButton = [StatusButton buttonWithType:UIButtonTypeCustom];
testButton.frame = CGRectMake(xPos, 110, 28, 28);
testButton.btnTreatment = t;
// match status of the RX to the correct button
if ([t.status intValue] == NotSeen) {
[testButton setImage:[UIImage imageNamed:#"toSee"] forState:UIControlStateNormal];
testButton.linkNumber = NotSeen;
}
else if ([t.status intValue] == SeenNotCharted) {
[testButton setImage:[UIImage imageNamed:#"seenNotCharted"] forState:UIControlStateNormal];
testButton.linkNumber = SeenNotCharted;
}
else if ([t.status intValue] == SeenCharted) {
[testButton setImage:[UIImage imageNamed:#"seenCharted"] forState:UIControlStateNormal];
testButton.linkNumber = SeenCharted;
}
else if ([t.status intValue] == NotSeeing) {
[testButton setImage:[UIImage imageNamed:#"notSeeing"] forState:UIControlStateNormal];
testButton.linkNumber = NotSeeing;
}
else if ([t.status intValue] == NotSeeingDC) {
[testButton setImage:[UIImage imageNamed:#"notSeeingDischarged"] forState:UIControlStateNormal];
testButton.linkNumber = NotSeeingDC;
}
[testButton addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:testButton];
xPos = xPos + 36;
}
}
}
return cell;
}
The image is correct size so no need to scale the image.
Occurs in simulator and on device.
After looking more closely, the inside of the images are sharp! So this issue has to do with the transparency for my circle shape of a button within a square button!
You are dequeuing a cell, then you add your buttons to the dequeued cell.
Those buttons never get removed. When you scroll up and down cells that go off screen are put on the dequeue queue. At this time they still have the buttons, then they are dequeued and you add more buttons. You have many buttons above each other, and that's why it looks blurry and your memory footprint gets bigger.
I would add the buttons from inside the cell. Save them in a array so you can remove them later. Then I would add a method to set the number of buttons you'll need. Like this:
// header
#property (strong, nonatomic) NSMutableArray *buttons;
// implementation
- (void)setNumberOfButtons:(NSInteger)numberOfButtons withTarget:(id)target selector:(SEL)selector {
// remove existing buttons from view
[self.buttons makeObjectsPerformSelector:#selector(removeFromSuperview)];
// "save" existing buttons in a reuse queue so you don't have to alloc init them again
NSMutableArray *reuseQueue = self.buttons;
self.buttons = [NSMutableArray arrayWithCapacity:numberOfButtons];
for (NSInteger i = 0; i < numberOfButtons; i++) {
UIButton *button = [reuseQueue lastObject];
if (button) {
[reuseQueue removeLastObject];
}
else {
button = [UIButton buttonWithType:UIButtonTypeCustom];
// you should always use the same target and selector for all your cells. otherwise this won't work.
[button addTarget:target action:selector forControlEvents:UIControlEventTouchUpInside];
}
[self.buttons addObject:button];
button.frame = ....
// don't set up images or titles. you'll do this from the collectionView dataSource method
}
}
you would then set the number of buttons in collectionView:cellForItemAtIndexPath: and configure each button according to your needs. something along those lines:
- (UICollectionViewCell*) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
Cell *cell = ... dequeue ...
Object *object = ... get from your backend ...
/* configure your cell */
if ([cell.buttons count] != object.numberOfItems) {
// no need to remove and add buttons if the item count stays the same
[cell setNumberOfButtons:object.numberOfItems withTarget:self selector:#selector(buttonPressed:)];
}
for (NSInteger i = 0; i < [object.numberOfItems count]; i++) {
UIButton *button = cell.buttons[i];
[button setImage:... forState:UIControlStateNormal];
}
}
And the action would look like this:
- (IBAction)buttonPressed:(UIButton *)sender {
UICollectionView *collectionView;
CGPoint buttonOriginInCollectionView = [sender convertPoint:CGPointZero toView:collectionView];
NSIndexPath *indexPath = [collectionView indexPathForItemAtPoint:buttonOriginInCollectionView];
NSAssert(indexPath, #"can't calculate indexPath");
Cell *cell = [collectionView cellForItemAtIndexPath:indexPath];
if (cell) {
NSInteger pressedButtonIndex = [cell.buttons indexOfObject:sender];
if (pressedButtonIndex != NSNotFound) {
// do something
}
}
else {
// cell is offscreen?! why?
}
}
pretty straight forward. Get the indexPath, get the collectionViewCell, check which index the pressed button has

Resources