I modified a subview table cell using addsubview to include an additional image on the right (besides the one on the left). I had it working great until I added a search bar at the top. Somehow in doing that, the right image stopped displaying. I tried removing the search bar but have been unable to get the image to display. I have a feeling I made a typo inadvertently or somehow messed up the code.
Here is the method. It works except that the image on the right no longer displays. Would appreciate it if anyone can spot my error or suggest what is going wrong.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *protoCell = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:protoCell];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:protoCell];
}
// IDModel * item;
IDModel * item = nil;
// if no search
//item = [self.tableItems objectAtIndex:indexPath.row];
//following for search
if (tableView == self.searchDisplayController.searchResultsTableView) {
item = [searchResults objectAtIndex:indexPath.row];
} else {
item = [self.tableItems objectAtIndex:indexPath.row];
}
// Configure the cell...
cell.textLabel.text = item.name;
cell.detailTextLabel.text = item.sub;
cell.imageView.image = [UIImage imageNamed:item.pic];
//following crops and rounds image
//add image to right
UIImageView *rightimage;
rightimage = [[UIImageView alloc] initWithFrame:CGRectMake(225.0,0.0,80.0,45.0)];
rightimage.autoresizingMask=UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
// rightimage.image = [UIImage imageNamed:#"pic.jpg"];
[cell.contentView addSubview:rightimage];
rightimage.image = [UIImage imageNamed:item.pic];
return cell;
}
Thanks in advance for any suggestions.
One concern here is that you shouldn't add views to a UITableViewCell from the view controller. Table view cells are reused, so each time this cell gets reused you'll be adding a new view to it without first removing the old one.
Instead, create a UITableViewCell subclass, and add rightimage (which I would rename rightImageView to be consistent with Apple's naming conventions) in the -initWithStyle:reuseIdentifier: method. Then set the rightView's frame in the -layoutSubviews method, or set up the auto layout constraints in the -initWithStyle:reuseIdentifier: right after creating the rightImageView.
Make rightImageView a public property (put it in the .h file) so you can assign the image from the view controller.
Related
I have created a custom UITableViewCell with a label on the far left (respects the parent margins) and it displays correctly. However, when I set an image using imageView.image (from the UITableViewCell), the label does not move to the right and so the label and the image are on top of each other. Any ideas how to make the label behave like the default label where it will move to the right to make way for the image?
If you create the cell from storyboard make sure you have set the UITableViewCell style to Custom.
Edit:
I saw your comment above.
If you don't wish to create a custom UITableViewCell class, you can still use default UITableViewCell with style set to Basic
So you can obtain its properties:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = #"Your text";
cell.imageView.image = [UIImage imageNamed:#"Your image name"];
UISwitch *mySwitch = [[UISwitch alloc] initWithFrame: CGRectZero];
cell.accessoryView = mySwitch;
// Define the state of the switch because the cell will get recycled as you scroll.
BOOL isOn;
[mySwitch setOn:isOn];
return cell;
}
The other solution is mentioned as commented above: You have to subclass UITableViewCell, drag and drop 3 IBOutlets and reference them in .h file.
I have a custom cell for my UITableView ; that custom cell comes from a class that extends UITableViewCell.
There is only a .xib where i crated the actual cell, and the links to these items in the .h.
I'm not using the .m, it's only the autogenerated awakeFromNib and setSelected:selected:animated in there.
When i create my cell in the cellForRow method, it's all fine, it appears correctly on the screen.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"CustomCellTableViewCell";
CustomCellTableViewCell *cell = [self.tbUpcomingEvents dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
tmp = [_eventList objectAtIndex:indexPath.row];
cell.lbDescription.text = tmp.description;
cell.lbTitle.text = tmp.title;
cell.imageView.layer.cornerRadius = 20;
cell.imageView.clipsToBounds = YES;
cell.layer.masksToBounds = YES;
cell.imageView.image = [UIImage imageNamed:tmp.type.typeImage];
cell.lbTimeStart.text = [[[timeFormatter stringFromDate:tmp.startTime] stringByAppendingString:#" - "]stringByAppendingString:[dateFormatter stringFromDate:tmp.startDate]];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
My issue is the following : when I start scrolling the tableview, the NEW cells are messed up, specifically the image. It simply gets bigger/wider and (obviously) deformed. I don't really know what caused it or how to fix it.
The cell is associated with the reuse identifier from the cellForRow method and the custom class in the .xib file. The UITableView has nothing in particular (and has no other link than the storyboard -> .h, delegate, datasource)
Any clue?
I found my issue. In this specific case, my imageView in my customCell.h was called "imageView". Which is a reserved named and, i guess, created conflicts at (some?) points in the creation of the cells.
I don't know the why's, but i know what fixed the issue. Now i've simply put another property name for my image and i'm golden ;)
Try to replace your code:
cell.lbDescription.text = tmp.description;
cell.lbTitle.text = tmp.title;
cell.imageView.image = [UIImage imageNamed:tmp.type.typeImage];
cell.lbTimeStart.text = [[[timeFormatter stringFromDate:tmp.startTime] stringByAppendingString:#" - "]stringByAppendingString:[dateFormatter stringFromDate:tmp.startDate]];
from cellForRowAtIndexPath to willDisplayCell method.
The idea is to make UITableViewCells templates in tableView:cellForRowAtIndexPath:, but to fill cells with particular values in tableView:willDisplayCellForRowAtIndexPath:.
uncheck autoresize subviews in interface builder
Newbie question.
I have a custom UICollectionView cells with UIImage and UIButton in every cell. I need to have array of UIImages that will be filled after cell's checkbox will be tapped to "checked" state (custom UIButton with appropriate checked/unchecked images connected to IBAction with changing internal cell's BOOL and checkbox state image). I can't use -didSelectItemAtIndexPath: for marking because I'm using it for previewing a cell photo. First idea was to add cell image to NSMutableArray by action of tapping checkbox to "checked" state, but if user will want to uncheck checkbox I can't track what exactly UIImage I need to delete from array. What is most painful method to do this?
PS: it is a listing of my method connected to the checkbox
- (void)theCheckboxTapped:(UIButton*)sender
{
cell = (CustomCell *)sender.superview.superview;
if (cell)
{
if ([cell isSelected] == NO)
{
UIImage *img1 = [UIImage imageNamed:#"checked.png"];
[[(CustomCell *)cell checkboxSign] setImage:img1 forState:UIControlStateNormal];
}
if ([cell isSelected] == YES)
{
UIImage *img2 = [UIImage imageNamed:#"unchecked.png"];
[[(CustomCell *)cell checkboxSign] setImage:img2 forState:UIControlStateNormal];
}
cell.isSelected =! cell.isSelected;
}
}
First idea was to made array of cells and check does BOOl of this cell is equal to YES or NO and add appropriate cell images to array
For solving this there are many solutions. But the one which I am explaining, is easy but this consumes some little bit more memory than other methods.
Steps:-
Create two array with capacity cell count. add all images in this array and add only bool value false initially when no cell is select. For this you can add 0.
NSMutableArray *imageArray = [[NSMutableArray alloc]init];
NSMutableArray *boolArray = [[NSMutableArray alloc]init];
When you checked any cell button then replace 0 with 1 in boolArray array, and vice versa.
And reload table. During reloading if value in second array for that position is 0 then no need to pick image from second and if value is 1 then pick image.
for changing value you can replaceObjectAtIndex method of nsmutablearray.
Edit:
No need to do like above.
one simpler solution is according to your code here.
As I am seeing that you are able to get cell.
So you can set tag for imageView and depending to tag you can also get cell's imageview in which you want to add image.
For this create imageArray and all images in this. Now add image like:
if cell.selected = True;
cell.imageView.image = [imageArray objectAtIndex:#"Cell's tage here or buttons tag here which is equal to indexPath.row"];
else
cell.imageView.image = #"Default image or no image here".
i have solved in a simple way.
Only after load 50-60 image uiCollectionView became very slow, so i have write a method to remove all imageView from the existing cell.
-(void)cleanCache{
NSMutableArray *visibleThumbViews = [NSMutableArray arrayWithCapacity:self.collectionView.visibleCells.count];
for (ThumbCell *t in self.collectionView.visibleCells) {
[visibleThumbViews addObject:t.thumbView];
}
for (ThumbView *t in self.thumbsViews) {
if (![visibleThumbViews containsObject:t]) {
[t unloadImage];
[t removeFromSuperview];
}
}
}
this method is called here:
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row % 30 == 0) {
[self cleanCache];
NSLog(#"clean");
}
ThumbCell *cell = [cv dequeueReusableCellWithReuseIdentifier:#"ThumbCellID" forIndexPath:indexPath];
cell.thumbView = [self.thumbsViews objectAtIndex:indexPath.row];
cell.thumbView.frame = cell.bounds;
return cell;
}
it's work very fine :P
sorry for bad english
UPDATE:
i had missed this delegate method:
-(void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath{
ThumbView *t = [self.thumbsViews objectAtIndex:indexPath.row];
[t unloadImage];
[t removeFromSuperview];
}
I have a UITableViewCell, it is scroll-disabled and with fixed sections and rows.
There are two sections, with 1 row in section 0, and several rows in section 1.
The tableView is for users to make some choices.
So, the first section (with only one row) is going to display the result of users' choices,
and no doubt the second section (with several rows) is for choosing.
Now I want to put an image in the cell of the only row of the first section,
and this image will change according to users' choose.
It is very easy to judge which png image should be displaying, but I have trouble update it.
I tried use the cell's imageView, and manually alloc a UIImageView or UIView there to display those images.
But all of them won't work, I mean they just keep what they are displaying at the beginning and never changes it, even if I set the view's background or its image to a new png.
I tried some method like
[myImage setNeedsDisplay] for the manually alloced view,
or
[thatCell setNeedsDiaplsy] & [self.tableView reloadData] for the imageView of that cell,
but in vain.
So I wonder how can I achieve this function that dynamically display an image in a UITableViewCell in different situations?
Thanks a lot!
_____update line_____
I'm sorry that I didn't provide my code.
and here they are.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *inOutTableCellIdentifier = #"DealTableViewIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:inOutTableCellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1
reuseIdentifier:inOutTableCellIdentifier] autorelease];
cell.textLabel.font = [UIFont fontWithName:cMyFont size:[UIFont systemFontSize]];
cell.detailTextLabel.font = [UIFont fontWithName:cMyFont size:[UIFont smallSystemFontSize]];
// I tried using both imageView and UIView here, but won't work
if (indexPath.section == 0) {
//cell.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"moneyCell.png"]];
cell.backgroundColor = [UIColor cyanColor];
// cell.imageView.image = [UIImage imageNamed:#"dealDone2.png"];
self.undoneIcon = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)] autorelease];
//self.undoneIcon.image = [UIImage imageNamed:#"dealUndone2.png"];
self.undoneIcon.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"dealUndone2.png"]];
[cell.contentView addSubview:self.undoneIcon];
.... // deal with other rows in section 1
return cell;
}
// and this is the method that update the image, the images are named "dealDoneX.png",
// where X is an integer from 0 to 4.
- (void)checkUndoneDegree { // here I also tried 2 ways corresponding to UIView or a cell's imageView, but neither works well.
int i = 0;
if (self._date)
i++;
if (self.moneyTextField.text)
i++;
if (self._incomingAccount)
i++;
if (self._expensingAccount)
i++;
if (_dealType != kTransferView)
if (self._type)
i++;
NSLog(#"undone degree: %d",i);
NSString *imageName = [#"dealUndone" stringByAppendingFormat:#"%d",i];
self.undoneIcon.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:imageName]];
[self.undoneIcon setNeedsDisplay];
// NSUInteger p[2] = {0,0};
// UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathWithIndexes:p length:2]];
// [cell setNeedsDisplay];
}
and everytime I update the table's data, like changing some text of some cell,
I would call [self checkUndoneDegree] and then call [self.tableView reloadData],
But the picture is never updated, at least from the screen.
I even tried to put the codes that decide which png to set in the
(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
method, but it can only make the view displaying the first png, without any updating.
Thanks for helping!
Make your undoneDegree (represented by i variable in your code) an ivar of your view controller, so it is accessible in all of it's methods, also in the UITableView delegate and data source methods.
Forget about setNeedsDisplay method. Since you are using UITableView to display your content, you need to play by its rules. This means you should use reloadSections:withRowAnimation: method.
Check again if you need self.undoneIcon. I'm pretty sure that imageView property should do. That is if you really want to display an image in the cell. If you want to create some kind of progress bar by manipulating cell's background, then use backgroundView property, or just place UIProgressView in your cell. This is what I think your want to do, after looking at your code.
I've created a custom UITableViewCell class, and used the layoutSubviews method to add a custom label. Like this:
- (void)layoutSubviews
{
[super layoutSubviews];
if (statusLabel == nil)
{
statusLabel = [[UILabel alloc]initWithFrame:CGRectMake(430.0, 10.0, 100.0, 20.0)];
[statusLabel setTextAlignment:UITextAlignmentRight];
[statusLabel setText:#"Status, set in code"];
statusLabel.tag = 1;
[self.contentView addSubview:statusLabel];
}
}
As you can see, I have set the initial text of the label to "Status, set in code".
In the table view controller I set the text for this custom label in the cellForRowAtIndexPath method, like so:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
int index = [indexPath row];
NSString *introducerString =[introducers objectAtIndex:index];
NSArray *parts = [introducerString componentsSeparatedByString:#","];
static NSString *MyIdentifier = #"Requester";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[[DanceCardCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:MyIdentifier] autorelease];
}
UIImage *image = [UIImage imageNamed:#"1.jpg"];
[cell.imageView setImage:image];
cell.textLabel.text = [parts objectAtIndex:1];
cell.detailTextLabel.text = #"Some text";
UILabel *statusLabel = (UILabel *)[cell viewWithTag:1];
statusLabel.text = #"Did it!";
return cell;
}
I'm using one table view to display two lists, depending on which of two buttons is pressed. When a button is pressed the appropriate table view controller is attached to the table view, and the reloadData method is called to trigger display of the new data. The new data does display, but the custom label text, which should read "Did it!" reads "Status, set in code ...", until I switch lists again twice.
How can I get the new text for the custom label to update straight away? I have checked the official documentation and cannot find any reference to refreshing a cell's display after updating its custom content.
Here is a screen shot to demonstrate what happens: http://www.dsbsystems.co.uk/images/xcode1.png
You're initializing the cell and immediately attempting to find the statusLabel with tag 1 inside it. layoutSubviews hasn't had the opportunity to be called yet, and so the label hasn't been created and added. (I suggest overriding the designated initializer method on your table view cell and creating the label there.)
Because of this, when you try to pull out statusLabel, it becomes nil because there's no such view, and messaging (calling a method on) nil simply does nothing (actually, it returns nil). You will need to watch out for this going forward if you're used to things blowing up with e.g. null reference exceptions.
When the cell is requested again, a new cell isn't needed because it's available from the reuse queue, and the label will be found correctly.