I want to update button images in my table view. When my table view initially loads, the button images are correct. But when I scroll down the new cells don't update to my new images; they simply reuse a random old image from the initial set. I have tried setImage and setBackgroundImage. Here is my cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0)
{
SSKGrooveCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"grooveCell" forIndexPath:indexPath];
SSKSongCellInfo *entry = [_objects objectAtIndex:indexPath.row];
NSArray *icons = [plistHelper iconsForGroove:entry.metadata.title];
NSString *icon = [icons objectAtIndex:0];
NSString *iconImgString = [NSString stringWithFormat:#"element_%#_grooves", icon];
NSString *iconImgWithExt = [NSString stringWithFormat:#"%#.png", iconImgString];
[cell.inst1Button setBackgroundImage:[UIImage imageNamed:iconImgWithExt] forState:UIControlStateNormal];
cell.titleLabel.text = entry.metadata.title;
return cell;
}
return nil;
}
For a quick test, add this line in your cellForRowAtIndexPath
cell.imageView.image = [UIImage imageNamed:iconImgWithExt];
Do you see correct images?
If no, check your images and image names
If yes, check your inst1Button IBOutlet connection.
I just came across this issue on an app. Turns out there's a bug in iOS 7.1 regarding a UIButton in a UITableView. You need to call setNeedsLayout on the button after you've set the image. E.g.:
[cell.inst1Button setNeedsLayout];
Related
I have a table view & a custom cell. the cell contains 3 buttons (check box type) . on button click the respective buttons text i need to change (check / uncheck).
I achieved this, but when i click 1st button on top cell and scroll down the new cell at the bottom also has this check mark, and when i scroll back to top the check mark is moved to next cell.. how to fix this??
code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *strCellIdentifier = #"RemoteCell";
RemoteCustomCell *cell = (RemoteCustomCell*)[tableView ![dequeueReusableCell][2]WithIdentifier:strCellIdentifier];
if (cell == nil) {
cell = [[RemoteCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:strCellIdentifier];
}
else {
cell = [cell initWithStyle:UITableViewCellStyleDefault reuseIdentifier:strCellIdentifier];
}
[cell.btnCheck1 addTarget:self action:#selector(CheckButton1_Click:) forControlEvents:UIControlEventTouchUpInside];
}
return cell;
}
- (void)CheckButton1_Click:(UIButton*)sender
{
RemoteControllCustomCell *clickedCell = (RemoteControllCustomCell *)[[sender superview] superview];
if(clickedCell.btnCheck1.selected)
{
[clickedCell.btnCheck1 setTitle:#"O" forState:UIControlStateNormal];
clickedCell.btnCheck1.selected = NO;
}
else
{
[clickedCell.btnCheck1 setTitle:#"X" forState:UIControlStateSelected];
clickedCell.btnCheck1.selected = YES;
}
}
screenshot:
In your RemoteCustomCell.m file you should implement
- (void)prepareForReuse
{
[super prepareForReuse];
cell.btnCheck1.selected = NO;
}
This way every cell that is reused will have it's btnCheck1.selected value set to NO, and when you load your cell in cellForRowAtIndexPath it will only set it to YES when the cell comes visible and you set it to that.
But it is key to store all your values in an NSMutableArray. There is no such thing as storing your values in the cells only, they get reused on a basis that can not be foreseen. Add your values to the array and use [myArray objectAtIndex:indexPath.row]; to open those values in a cell.
An example:
Somewhere in viewDidLoad
NSMutableArray *myArray = [[NSMutableArray alloc] initWithObjects:#"1", #"0", #"1", #"1", nil];
In your cellForRowAtIndexPath
BOOL yesOrNo = [[myArray objectAtIndex:indexPath.row] boolValue];
And then set your button.selected to the boolean.
This is a typical issue, where you are relying on the UI to the job of your model. The model, the thing that you should pass to your UITableViewCell, so it can be built, would tell it, if it should be displaying an "X" or an "O". Since you are not doing this, the easiest solution, would be to simply reset the state of the cell everytime it gets dequeued.
I think you need to store the state in a array and check the state in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
CheckButton1_Click do change the state, but when dequeueReusableCell , it loads from cellForRowAtIndexPath again.
It seems like you have dequeue of cell issue. You may implement cellForRowAtIndexPath method as below.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"RemoteCell";
RemoteCustomCell *cell = (RemoteCustomCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell==nil) {
NSArray *arrNib=[[NSBundle mainBundle] loadNibNamed:CellIdentifier owner:self options:nil];
cell= (RemoteCustomCell *)[arrNib objectAtIndex:0];
}
[cell.btnCheck1 addTarget:self action:#selector(CheckButton1_Click:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
With iOS 8 I have come up with some issues using UITableView. In fact, I have a NavigationController and its RootController set as my ViewController with UITableView. Then I configure my table, add cells and set their style to UITableViewCellStyleValue1 and nothing happens at the time it should display a detailed text label to the right of the textLabel. I suppose that there is some missing constraints preventing from displaying the whole cell's view.
My code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"STI";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier];
}
cell.textLabel.text = self.dwarves[indexPath.row];
cell.detailedLabel.text = #"Detailed text";
UIImage *img = [UIImage imageNamed:#"star"];
cell.imageView.image = img;
return cell;
}
What I get:
I think the property you're looking for is cell.detailTextLabel, not cell.detailedLabel.
Take a look at this post.
The code I use for setting up my detailed text:
if (indexPath.row < 7) {
cell.detailTextLabel.text = #"First";
} else {
cell.detailTextLabel.text = #"Second";
}
I'm in the process of updating an old app for iOS 8 and ran into the same issue. I haven't discovered the root of the problem yet, but calling layoutSubviews for the cell before returning it fixed it for me.
...
[cell layoutSubviews];
return cell;
}
The button action is SongsSelectionSongs_Click. When I click this button, the button image changing, the button tap count is getting correct and after selected button images also changing, but when I scroll back and forth in the UITableView the button image seems to be randomly changing.
This is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"SongsTAbleViewCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SongsTAbleViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
btn_songSelect.tag = indexPath.row;
lbl_songLabel.text = [[arr_tablVArray objectAtIndex:indexPath.row] objectForKey:#"SongTitle"];
lbl_artistLabel.text = [[arr_tablVArray objectAtIndex:indexPath.row] objectForKey:#"SongArtist"];
return cell;
}
-(IBAction)SongsSelectionSongs_Click:(id)sender
{
UIButton *button = sender;
CGPoint correctedPoint = [button convertPoint:button.bounds.origin toView:self.tblv_SongslisttableView];
NSIndexPath *indexPath = [self.tblv_SongslisttableView indexPathForRowAtPoint:correctedPoint];
NSLog(#"Button tapped in row %d",indexPath.row);
SelectedAlbumUrl = [[arr_tablVArray objectAtIndex:indexPath.row] objectForKey:#"SongUrl"];
str_songtitle = [[arr_tablVArray objectAtIndex:indexPath.row] objectForKey:#"SongTitle"];
if ([[button backgroundImageForState:UIControlStateNormal] isEqual:[UIImage imageNamed:#"add.png"]])
{
btn_songsShareButton.userInteractionEnabled = YES;
[btn_songSelect setBackgroundImage:[UIImage imageNamed:#"remove.png"] forState:UIControlStateNormal];
buttonStatus = buttonStatus +1;
[btn_songsShareButton setImage:[UIImage imageNamed:#"share selected.png"] forState:UIControlStateNormal];
}
else
{
[btn_songSelect setBackgroundImage:[UIImage imageNamed:#"add.png"] forState:UIControlStateNormal];
buttonStatus = 1;
[btn_songsShareButton setImage:[UIImage imageNamed:#"share unselected.png"] forState:UIControlStateNormal];
}
}
You are not doing anything within your cellForRowAtIndexPath to select or deselect image. When you reuse a cell, it doesn't change the state of the cell unless you explicitly tell it to in cellForRow. Therefore, it will either reuse a selected or deselected cell (whatever is the first available reusable cell) and put that on the screen as-is.
To fix this issue, you need logic in your cellForRowAtIndexPath method to either select or deselect the image based on what is appropriate.
In general, if your problem has anything to do with "my cells don't show up right when scrolling" odds are you're not reusing your cells properly.
EDIT: in response to your comment, no, I will not rewrite your code. But I will give you some direction.
I would recommend keeping an additional key/value on your arr_tablVArray that will track whether or not the "share" should be enabled or disabled (I would suggest a bool value). This would make it so that you could check whether or not the "share" is enabled/disabled by checking a bool instead of checking the contents of the button's image in your IBAction method.
This info would now be available in your cellForRowAtIndexPath method as well, and you could check the value for the current record in arr_tablVArray and set your images accordingly just like you set your lbl_songLabel and lbl_artistLabel.
//Try It, it's Working Fine
pragma .h File
NSMutableArray * rowIdArray;
pragma .M File
#synthesize rowIdArray;
- (void)viewDidLoad
{
rowIdArray=[[NSMutableArray alloc]init];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [NamesArray count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
ViewControllerCell *cell = (ViewControllerCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
NSArray *nib;
nib = [[NSBundle mainBundle] loadNibNamed:#"ViewControllerCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
// Configure the cell...
cell.nameslbl.text = [NamesArray objectAtIndex:indexPath.row];
cell.nameBtn.tag=indexPath.row;
[cell.nameBtn addTarget:self action:#selector(NamesClick_Tapped:) forControlEvents:UIControlEventTouchUpInside];
NSString *a=[NSString stringWithFormat:#"%d", indexPath.row];
NSString *b=[[NSString alloc]init];
for (int i=0;i<[rowIdArray count];i++)
{
b=[rowIdArray objectAtIndex:i];
if ([a isEqualToString:b])
{
UIImage *buttonImage = [UIImage imageNamed:#"star_selected.png"];
[cell.nameBtn setBackgroundImage:buttonImage forState:UIControlStateNormal];
}
}
return cell;
}
-(IBAction)NamesClick_Tapped:(id)sender
{
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.NameTableView];
NSIndexPath *indexPath = [self.NameTableView indexPathForRowAtPoint:buttonPosition];
NSString *rowIdStr = [NSString stringWithFormat:#"%d", indexPath.row];
if(![rowIdArray containsObject:rowIdStr])
{
[rowIdArray addObject:rowIdStr];
}else{
[rowIdArray removeObject: rowIdStr];
}
[self.NameTableView reloadData];
}
when you reuse a cell where the button has been already set, the same button appears with the previously set image. Instead of creating a new button every time you need a cell, you should just be resetting the state of an existing button. This link might help you.
I'm new in iOS programming, and I have a strange problem...
I created a tableview, add cells with "subtitle" style. In my code, I can set the image, all works fine. the code (g, gf and picturesArray are strings array) :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString * cellIdentifier = #"fCellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
NSString *feed = [self.g objectAtIndex:indexPath.row];
NSString *feed1 = [self.gf objectAtIndex:indexPath.row];
NSString *feed2 = [self.picturesArray objectAtIndex:indexPath.row];
[cell.textLabel setText:feed];
[cell.detailTextLabel setText:feed1];
cell.imageView.image = [UIImage imageNamed:feed2];
return cell;
}
Next, I want to go to a new view when I click on a cell. Here the code :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
GUDdfViewController *detail = [self.storyboard instantiateViewControllerWithIdentifier:#"GUdfView"];
detail.titleString = [self.gf objectAtIndex:indexPath.row];
detail.descriptionString = [self.gfs objectAtIndex:indexPath.row];
detail.contentString = [self.gfc objectAtIndex:indexPath.row];
detail.imageNameString = [self.picturesArray objectAtIndex:indexPath.row];
[self.navigationController pushViewController:detail animated:YES];
}
OK. All works; in my new view, title and subtitle are present with good content.
BUT ! the image is not displayed... Here the line where I set the image in "GUDdfViewController" :
[self.pictureLogoOutlet setImage:[UIImage imageNamed:self.imageNameString]];
When I use NSLog, it says me that my object (pictureLogoOutlet.image) is null. I also tried this :
[self.pictureLogoOutlet setImage:[UIImage imageNamed:#"baguette.png"]];
but the problem is the same...
Do you know why I have this problem ? I really don't understand.
pictureLogoOutlet in nil because your GUDdfViewController has not yet initialized its IBOutlets.
You have to create property of UIImage to your viewocntroller and using that property load imageView in your GUDdfViewController's viewDidLoad.
I've added a UIImage to my table view cell. However, the UIImage is pushing the separator over to the right to make room for the UIImage. I'd like to find a way to have the separator include the UIImage and not be pushed over. Here is a picture of my table view cell.
Here is my cellForRowAtIndexPath method with code for the image:
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
Exercise *tempPlaceholder = [exercisesInTable objectAtIndex:indexPath.row];
NSString *exerciseDisplayName = tempPlaceholder.exerciseName;
exerciseDisplayName = [exerciseDisplayName capitalizedString];
exerciseDisplayName =
[exerciseDisplayName stringByReplacingOccurrencesOfString:#"_"
withString:#" "];
cell.textLabel.text = exerciseDisplayName;
cell.imageView.image = [UIImage imageNamed:#"quads.png"];
return cell;
}
If anyone could help me with this I'd really appreciate it. Thank you.
For anyone else who runs into this problem, using:
[self.tableView setSeparatorInset:UIEdgeInsetsZero];
will fill the gap between the UIImage and the table cell separator.
Try change the size of imageView frame
cell.imageView.frame = CGRectMake(0, 0, 10.0, 10.0);
Or change the height of cell
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 40.0;
}
The behaviour you are experiencing will only occur on iOS 7 where the separators have insets that by default change with image view size.
To remove this behaviour simply set the separator insets to zero. However the separatorInset property is available on UITableView from iOS 7.0
So you only have to remove the inset in iOS 7.
You can check whether the table view responds to setSeparatorInset: doing
if ([self.tableview respondsToSelector:#selector(setSeparatorInset:)])
{
[self.tableview setSeparatorInset:UIEdgeInsetsZero];
}