I'm having problems implementing a table row that allows text to wrap to multiple lines, and also has an image on the left, and a disclosure accesssory on the right.
The multiline text is fine but the imageView expands to the right when there is more than one line of text. I want images in all rows to be the same size. I've tried setting the autoresizingMask to UIViewAutoresizingNone but this doesn't seem to work.. Do I need to use the contentView, or a nib file?
Any help/example code appreciated!
If all off your images are different size then you should think of adding a ImageView as Subview to cell. Keep Labels depending on the Imageview.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
UIImageView *cellImage;
UILabel *label;
UILabel *detailLabel;
cell = [tableView dequeueReusableCellWithIdentifier:#"cell"]; //Create cell
if(cell == nil)
{
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"cell"] autorelease];
cellImage = [[[UIImageView alloc] initWithFrame:CGRectMake(3, 3, 44, 44)] autorelease];
label = [[[UILabel alloc] initWithFrame:CGRectMake(55, 4, 260, 20)] autorelease];
label.font = [UIFont boldSystemFontOfSize:15.0];
label.tag=25;
detailLabel = [[[UILabel alloc] initWithFrame:CGRectMake(55, 25, 260, 15)] autorelease];
detailLabel.font = [UIFont systemFontOfSize:13.0];
detailLabel.tag=30;
[cell.contentView addSubview:cellImage];
[cell.contentView addSubview:label];
[cell.contentView addSubview:detailLabel];
cell.accessoryType =UITableViewCellAccessoryDisclosureIndicator;
}
else
{
cellImage = (UIImageView *)[cell.contentView viewWithTag:20];
label = (UILabel *)[cell.contentView viewWithTag:25];
detailLabel = (UILabel *)[cell.contentView viewWithTag:30];
}
cell.image = [arrayContainingImages objectAtIndex:indexPath.row];
label.text =[arrayContaininglabeltext objectAtIndex:indexPath.row];
detailLabel.text=[arrayContainingDetailLabelText objectAtIndex:indexPath.row];
return cell;
}
pls see Stop image expanding in multiline table row? #2
Related
I am using table view using custom coding with tag method to save memory.
I was successful to show data in the view but the problem is if 10 cells are showing and then if I scroll down like for one cell then it should show 2-11 cell data but it switches to 1-10 again.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
UILabel *cellNAMElabl = nil;
UILabel *cellDetaillabl = nil;
UIImageView *imgView = nil;
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
cellNAMElabl = [[UILabel alloc] initWithFrame:CGRectMake(88, 10, 150, 20)];
[cellNAMElabl setTag:1];
cellNAMElabl.text = [name5 objectAtIndex:indexPath.row];
UIFont *myFont1 = [ UIFont fontWithName: #"Arial" size: 20.0 ];
cellNAMElabl.font = myFont1;
[cell.contentView addSubview:cellNAMElabl];
cellDetaillabl = [[UILabel alloc] initWithFrame:CGRectMake(88, 28, 150, 20)];
[cellDetaillabl setTag:2];
cellDetaillabl.text = [email5 objectAtIndex:indexPath.row];
UIFont *myFont = [ UIFont fontWithName: #"Arial" size: 13.0 ];
cellDetaillabl.font = myFont;
[cell.contentView addSubview:cellDetaillabl];
imgView=[[UIImageView alloc] initWithFrame:CGRectMake(25, 5, 52, 50)];
[imgView setTag:3];
imgView.image = [imagepath5 objectAtIndex:indexPath.row];
[cell.contentView addSubview:imgView];
}
cellNAMElabl = (UILabel *)[cell viewWithTag:1];
cellDetaillabl = (UILabel*)[cell viewWithTag:2];
imgView = (UIImageView*)[cell viewWithTag:3];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
You are not assigning new content to subviews, if they have been already created. After the case if(cell == nil), these you have just got references.
cellNAMElabl = (UILabel *)[cell viewWithTag:1];
cellDetaillabl = (UILabel*)[cell viewWithTag:2];
imgView = (UIImageView*)[cell viewWithTag:3];
Here when cell is not nil, you are just getting references to labels and imageview, but you are not setting new text and image from data source. Add following lines and remove them from the if (cell == nil) part:
cellNAMElabl.text = [name5 objectAtIndex:indexPath.row];
cellDetaillabl.text = [email5 objectAtIndex:indexPath.row];
imgView.image = [imagepath5 objectAtIndex:indexPath.row];
[cell.contentView addSubview:imgView];
The way this dequeueReusableCellWithIdentifier works: If iOS detects that a cell is not displayed anymore, then dequeueReusableCellWithIdentifier will return that cell. If there is no unused cell, it returns nil. So what you need to do:
If dequeueReusableCellWithIdentifier returns nil, then you create a new cell, and you do all the setup that is required for all cells with the same identifier. For example, add view tags like you did, set fonts, colors etc.
Then, whether you use a cell returned by dequeueReusableCellWithIdentifier or one that you just created yourself, you add all the information that is used for the specific section/row that you want to display. So if row 1, row2, and so on display different text, then you set the text here. That's what you didn't do, so when a cell was reused, you didn't set the new text for it.
So the idea is that all the work that is the same for all rows is only done once when a cell is created, and only as many cells are created as is needed to display them on the screen. The work that is different from row to row is done for each row, as it is needed.
If you set a breakpoint in the if cell == nil block its probably only being hit for the first set if your reuseID is correct. Thats why its never getting a chance to set any new data into the cell.
You should not look for a nil cell, rather use a correct reuseID and a prototype cell in IB that is set to a custom UITableViewCell subclass you create.
Its also good practice to implement prepareForReuse on custom cells, where you clear any cell data e.g. label.text = nil, imageview.image = nil
This way you dont get invalid data from previously dequeued cells. It might not solve the question directly, but it would have wiped the fixed data set in your if cell == nil block to help debug.
What you want to do is..
add/setup the tableViewCell UI if the cell is nil..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
UILabel *cellNAMElabl = [[UILabel alloc] initWithFrame:CGRectMake(88, 10, 150, 20)];
cellNAMElabl.tag = 1;
cellNAMElabl.font = [UIFont fontWithName: #"Arial" size: 20.0 ];
[cell.contentView addSubview:cellNAMElabl];
UILabel *cellDetaillabl = [[UILabel alloc] initWithFrame:CGRectMake(88, 28, 150, 20)];
cellDetaillabl.tag = 2;
cellDetaillabl.font = [UIFont fontWithName: #"Arial" size: 13.0 ];
[cell.contentView addSubview:cellDetaillabl];
UIImageView *imgView=[[UIImageView alloc] initWithFrame:CGRectMake(25, 5, 52, 50)];
imgView.tag = 3;
[cell.contentView addSubview:imgView];
}
//and just update your data if the cell is currently exist and not nil..
//you already called the view using tag so, you dont need those:
// UILabel *cellNAMElabl = nil;
// UILabel *cellDetaillabl = nil;
// UIImageView *imgView = nil;
((UILabel *)[cell viewWithTag:1]).text = [name5 objectAtIndex:indexPath.row]; // cellNAMElabl
((UILabel*)[cell viewWithTag:2]).text = [email5 objectAtIndex:indexPath.row]; // cellDetaillabl
((UIImageView*)[cell viewWithTag:3]).image = [imagepath5 objectAtIndex:indexPath.row]; // imgView
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
hope this have help you, happy coding cheers!
As I scroll up and down the table view the data in each cell becomes duplicated and unreadable. Does anyone have any suggestions for the below?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateStyle:NSDateFormatterShortStyle];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
UILabel *label1 = [[UILabel alloc]initWithFrame:CGRectMake(10, 12, 250, 20)];
UILabel *label2 = [[UILabel alloc]initWithFrame:CGRectMake(250, 12, 50, 20)];
label1.tag= 666;
label2.tag= 666;
[cell.contentView addSubview:label1];
[cell.contentView addSubview:label2];
// Configure the cell...
President *p = (President *)[self.importedRows objectAtIndex:indexPath.row];
label1.text = p.no;
label2.text = p.name;
UILabel* cellLabel = (UILabel*)[cell viewWithTag: 666];
cellLabel.text = [NSString stringWithFormat:p.no , p.name];
return cell;
}
dequeueReusableCellWithIdentifier caches the generated cells. So if you request a cell which you already created before this cell will NOT be generated again from scratch (meaning that the labels you added before already exists!).
So when adding the labels tag them with a unique number :
label1.tag= 666;
label2.tag= 667;
And before adding them to the cell remove them as follows :
UIView *labelView = [cell.contentView viewForTag:666];
if (labelView != nil) {
[labelView removeFromSuperView];
}
And do the same with the second label.
because you are adding label1 and label2 again and again to cell.
UILabel *label1 = [[UILabel alloc]initWithFrame:CGRectMake(10, 12, 250, 20)];
UILabel *label2 = [[UILabel alloc]initWithFrame:CGRectMake(250, 12, 50, 20)];
[cell.contentView addSubview:label1];
[cell.contentView addSubview:label2];
As the cell is reused, same cell is used for another row, and it already has label1,2. but you are creating label1,2 again and again and adding them to it.
Give different tags for label1,label2.Check if viewWithTag:666 and 667 is present.If not present add them as subview ,if already present, just get them using viewWithTag and change their text values.
The problem here is with below code:
UILabel* cellLabel = (UILabel*)[cell viewWithTag: 666];
cellLabel.text = [NSString stringWithFormat:p.no , p.name];
I have tried your code, commenting these two lines stop overlapping. You can try to change the frame of this label.
I suggest making your own subclass of UITableViewCell which has two UILabel's on it, then in the method you're using above, create instances of your subclass rather than UITableViewCell if the cell doesn't exist, then populate the labels.
In your custom cell implementation file, you'll have to override the 'prepareForReuse' method, and in it set the text of your labels to nil (#""). This properly uses the 'dequeueWithReuseIdentifier' functionality and only creates the labels when necessary, rather than only showing them when required.
A solution where you can gain performance is the following.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// create and add labels to the contentView
}
// retrieve and update the labels
Obviously you could also create your UITableViewCell subclass.
You could also try this swag (fresh answer, get your fresh answer!):
BOOL doesContain = [cell.subviews containsObject:imageView];
if (!doesContain)
{
[cell.contentView addSubview:imageView];
}
imageView.image = yourImage];
Also for a quick way to subclass all of your stuff, check my answer.
I seem to be having a problem understanding how subviews work. I have a UITextfield and I want to add this to the content view of a UITableViewCell so i do this:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
if (cell==nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
} // Configure the cell...
UITextField *tf = [textFieldsArray objectAtIndex:[indexPath row]];
tf.frame = CGRectMake(0, 0, 100, 12);
[cell.contentView addSubview:tf];
return cell;
}
I assumed that by making the textfields frames origin (0,0) when i add this as a subview to the content view, it will place it in the content view at position (0,0), but this is not happening, it is actually placing it at position (0,0) of the entire cell (the top left most part of the cell).
Unless this has been changed in iOS7, i thought the content view was like this:
(source: idev101.com)
If so, is there a way i can actually place this in the contentView without having to manually define an offset each time?
Try This
if (cell==nil)
{
cell = [[[UITableViewCell alloc]initWithStyle:
UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]autorelease];
UIImageView *img=[[UIImageView alloc]init];
img.tag=100;
img.layer.cornerRadius = 3;
img.layer.masksToBounds = YES;
[cell addSubview:img];
UILabel *lbl= [[UILabel alloc]init];
lbl.backgroundColor= [UIColor clearColor];
lbl.text=#"ABC";
lbl.textAlignment=NSTextAlignmentLeft;
lbl.textColor=[UIColor blackColor];
lbl.tag=200;
[cell addSubview:lbl];
}
img1=(UIImageView *)[cell viewWithTag:100];
NSArray *imgDataArr = [[NSArray alloc] initWithArray:[[arrFields objectAtIndex: storyIndex] objectForKey: #"image"]];
for (UIImage *image in imgDataArr)
{
if (image)
img1.image =image;
}
[cell addSubview:img1];
UILabel *lbl1 = (UILabel*)[cell viewWithTag:200];
[cell addSubview:lbl1];
lbl1.numberOfLines=3;
lbl1.text=[[arrFields objectAtIndex: storyIndex] objectForKey: #"Item_No"];
Apologies if this comes across as a beginner's question. I'm trying to populate a UITableView with sections and custom cell formatting.
i've debug this code and the label on each tag returns the correct value:
-(UITableViewCell *)cellForIndexPath:(NSIndexPath *)indexPath forData:(NSObject *)cellData {
static NSString *CellIdentifier = #"MatterWIPCell";
RVMatterWIPExceptionSummary *matterWIPSummary = (RVMatterWIPExceptionSummary *)cellData;
UITableViewCell *cell = [self.searchableTable dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
UILabel *label;
label = (UILabel *)[cell viewWithTag:1];
label.text = [[DataFormat dataFormat] stringLabelFormat: matterWIPSummary.fileNumber];
label = (UILabel *)[cell viewWithTag:2];
label.text = [[DataFormat dataFormat] stringLabelFormat: matterWIPSummary.clientName];
label = (UILabel *)[cell viewWithTag:3];
label.text = [[DataFormat dataFormat] stringLabelFormat: matterWIPSummary.matterTitle];
label = (UILabel *)[cell viewWithTag:4];
label.text = [[DataFormat dataFormat] currencyFormat:matterWIPSummary.workInProgress withDecimals:YES];
label = (UILabel *)[cell viewWithTag:5];
label.text = [[DataFormat dataFormat] stringLabelFormat:matterWIPSummary.matterDescription];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
return cell;
}
i have checked the storyboard it uses the same cell identifier.
Did i miss something so the data won't display even the cell never returns nil?
Thank You
Add [cell.contentView addSubview:label]; before the return cell; And of course declare label with something like this UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, 320, 25)];
In my iPhone application UITable having So many cells with Text. The Text size is more than the width of the device. How can I wrap the text in cell and display the text in the different lines or divide it in the lines?
You can add a UILabel as a subview of a cell in a
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
method. Then set its lineBreakMode and numberOfLines properties as you want. The code must look something like this:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:tID];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:tID] autorelease];
}
else{
UIView *tView = [cell viewWithTag:100];
[tView removeFromSuperview];
}
UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(40, 0, 90, 50)];
label.tag = 100;
label.numberOfLines = 2;
label.lineBreakMode = UILineBreakModeWordWrap;
label.text = #"Putyourverylongcelltexthere";
[cell addSubview:label];
[label release];