I have added a UILabel as the content view of my tableview. The text in the UILabel is overlapping upon scrolling. Below is the code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.chatTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Group"];
static NSString *CellIdentifier = #"Group";
UITableViewCell *cell = [self.chatTableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = self.latestTrimText;
UILabel *cellLabel = [[UILabel alloc]init];
cellLabel.text = self.dateOfLatestTrim;
cellLabel.frame = CGRectMake(15, 0, 150, 30);
[cell.contentView addSubview:cellLabel];
return cell;
}
I can fix this by changing to UITableViewCell *cell = [self.chatTableView dequeueReusableCellWithIdentifier:nil];
But then, the scrolling of the tableview won't be smooth. Is there another way to fix the issue?
The tableview cells are recycled and reused potentially an infinite amount of times. This is what the reuse identifier stands for.
Take care not to add any subview outside the if (cell==nil) block. Now you are just adding again and again a new label to the same cell instance. This is why your texts overlaps each other.
I would recommend you to read the documentation on how the cells are recycled and reused.
Your fix is not correct because by passing a nil reuse id, you are just preventing the recycling process to play. You create a new instance for each row of your tableview. This is why you have performance issues then.
Related
I use storyboard and Auto Layout. I add UISwitch to my cell with tag 5. When I choose first UISwitch and scroll down I see that other UISwitch is also turned on and if I scroll up my first UISwitch is turned off. How to fix this?
My code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
UISwitch* switchView = (UISwitch *)[cell viewWithTag:5];
[switchView addTarget:self action:#selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
return cell;
}
This is because UITableView reuse UITableViewCell so one cell can be use more than once in different indexPaths, in this situation its your responsibility to maintain the state of UITableViewCell subViews. Better place to do this is cellForRowAtIndexPath where you are returning cell add logic to make show/hide UISwitch or to select accurate state i.e. on or off, you can keep that flag in dataSource object and then you can check for that flag to make set right state for UISwitch
Try This:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellSetting";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.textLabel.text = [self.settingsArray objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
if ([[self.settingsArray objectAtIndex:indexPath.row] isEqualToString:ROW_PRIVATE_BROWSING])
{
self.privateBrowsingSwitch =[[UISwitch alloc]initWithFrame:CGRectMake(cell.frame.size.width-65, 10, 30, 30)];
if (ApplicationDelegate.privateBrowsing)
{
[self.privateBrowsingSwitch setOn:YES animated:YES];
}
[self.privateBrowsingSwitch addTarget:self action:#selector(changeSwitch:) forControlEvents:UIControlEventValueChanged];
[cell addSubview:self.privateBrowsingSwitch];
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
Every time cellForRowAtIndexPath is called you have to replace the specific data that needs to be displayed for a cell at that position. This includes things like labels, images and your UISwitch.
This occurs because UITableViews use a small number of cells that are reused.
In cellForRowAtIndexPath add something like this:
switchView.on = [self isSwitchOnForCellAtIndexPath:indexPath]
Then write whatever logic is required to determine if the switch should be on or not.
I am using UITextField, and every row have a CellLable and TextField. Lable and TextField data comes from array. While running the app, all data are comes fine but when scrolling the Tableview, Last 2-3 Rows unorganized.
NSMutableArray
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
ArrFieldData= [NSMutableArray arrayWithObjects:#"Fist Name", #"Last Name",#"User Name", #"Password",#"Confirm Password", #"Gender",#"DOB", #"Profile Pic",#"Deparment", #"Joining Date",#"Education", #"Role", nil];
Now cellForRowAtIndexPath Function
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
UITextField *txtField ;
if (cell ==nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
txtField = [[UITextField alloc]initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/3 + 40, 2, [UIScreen mainScreen].bounds.size.width/2, cell.layer.frame.size.height -5)];
[self setUpCell:cell withIndexPath:indexPath withTextField:txtField];
}
[self UpdateCell:cell withIndexPath:indexPath withTextField:txtField];
return cell;
}
SetUp Cell Function
-(void)setUpCell:(UITableViewCell *)cell withIndexPath:(NSIndexPath *)indexPath withTextField: (UITextField *)txtField {
cell.textLabel.text = [ArrFieldData objectAtIndex:indexPath.row];
cell.textLabel.font = [UIFont systemFontOfSize:12.0];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
txtField.tag = indexPath.row+1;
txtField.layer.borderColor = [UIColor grayColor].CGColor;
txtField.delegate = self;
txtField.layer.borderWidth = 1.0f;
txtField.layer.cornerRadius = 4.0f;
txtField.placeholder = cell.textLabel.text;
txtField.font = [UIFont systemFontOfSize:12.0];
[cell.contentView addSubview: txtField];
}
Update Cell Function
-(void)UpdateCell:(UITableViewCell *)cell withIndexPath:(NSIndexPath *)indexPath withTextField: (UITextField *)txtField {
[self setUpCell:cell withIndexPath:indexPath withTextField:txtField];
}
First time Running the application, It is showing all cell and textfield data are Serialize. but when scroll some cell and TextField are not serialize as per Array Value. I am attaching the Simulator Screenshot.
First Screenshot for First time running, and second for when i scroll the Tableview. See the last 4-5 cell and Textfield Placeholder text. They are un-organized. I want it shouldn't change.
As you are using reusable cells, like
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
UITextField *txtField ;
if (cell ==nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
txtField = [[UITextField alloc]initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/3 + 40, 2, [UIScreen mainScreen].bounds.size.width/2, cell.layer.frame.size.height -5)];
[self setUpCell:cell withIndexPath:indexPath withTextField:txtField];
}
[self UpdateCell:cell withIndexPath:indexPath withTextField:txtField];
return cell;
}
UITableView uses the concept of reusable cell to achieve maximum performance by reducing the memory consumption, and to exploit this feature of reusing cells you can use the above UITableView's API's to achieve that.
But before using any feature it's very important to understand the working and the usage of any feature.
In your above implementation of tableView: cellForRowAtIndexPath: method, you have used the concept of cell reusability.
If the cells doesn't exist and are created for the first time, than they are allocated(every subview is created and added on the content view of the cell), customized and initialized with the data from the data source of the respective index path.
But in case the cells are reused(as they were already created for any other index path), there subviews exist with the data already filled for the previous index path for which it was created.
Now there are two things we can do to use already created cell for the current index path,
1) if the cells contain subview with data then remove the subviews and recreate the new ones, customize and populate them with the data.
2) rather than releasing the previous subviews and creating new ones, refill the data for the data model of the corresponding index path.
In your case, if the cell is being created for any index path, than the text filed for it is also created and if it's reused than the new text field is not created and it's being reused from the previously created cell thus the issue of the placeholder text not matching with the left text.
So, in order to solve your problem I think you should either create the textfield when the cell is created and if the cells are reused than refill the data in the text filed from the data source of the corresponding index path.
Your problem is due to a feature of UITableView. When you scroll a UITableView the indexPath is updated so you are not getting the index values you are expecting from the tableView.
Instead of adding a UITextField programmatically. Create a Custom UITableViewCell and from the method cellForRowAtIndexPath: update the placeHolder of your UITextField. The tableView will take care of scrolling for you.
Use this code :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
UITextField *txtField ;
if (cell ==nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
cell.textField.placeholder= cell.textLabel.text;
}
cell.textField.placeholder= cell.textLabel.text;
return cell;
}
As soon as the table view gets touched the cell titles (and on-tap actions) disappear. I only use standard table view cells and store the values in an array. After the values disappear the table stays scrollable. Any ideas?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
cell.textLabel.text = [[systeme objectAtIndex:indexPath.row] description];
cell.backgroundColor = [UIColor clearColor];
[cell.textLabel setTextColor:[UIColor whiteColor]];
[cell.textLabel setTextAlignment:NSTextAlignmentCenter];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[[NSNotificationCenter defaultCenter] postNotificationName:#"choseSystem" object:[systeme objectAtIndex:indexPath.row]];
}
You should be sure that the reuse identifier is the same for all cells if you use only one type of cells. You should do something similar to the following in the portion of your code where to retrieve a reusable cell:
NSString *CellIdentifier = [NSString stringWithFormat:#"CellReuseIdentifier", (long)indexPath.section];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
And make you you set the #"CellReuseIdentifier" in your xib file or your storyboard.
If you would like to use multiple custom cells for a table view you should do something similar to what you're doing, but take into account that reuse identifiers need to be configured for every type of cells.
Hope this helps!
The table view was fine. I just added its view as a subview to another view without keeping reference to the actual UITableViewController. That was the problem.
I am having trouble removing the white border that appears between each cell inside my UITableView. I have tried using:
[myTableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
inside my viewDidLoad method, but unfortunately that does not seem to work. I am using a background image for my cells to display, and it is the border between these images that I wish to remove. The image itself is the size of each cell, and the size of each cell I set in my CustomTableViewCell class as follows:
self.contentView.frame = CGRectMake(0, 0, 320, 80);
My cellForRowAtIndexPath method is as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"mycell";
MyTableViewCell *cell = (MyTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[MyTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
cell.ID.text = [[DataModel sharedInstance].ID objectAtIndex:indexPath.row];
cell.Name.text = [[DataModel sharedInstance].Name objectAtIndex:indexPath.row];
cell.Date.text = [[DataModel sharedInstance].Date objectAtIndex:indexPath.row];
[cell setBackgroundView:[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Cell.png"]]];
return cell;
}
Despite everything I have done, I am seeing a clear white border between my cells in the table. I really would like to remove this. Can anyone see what I am doing wrong?
Inside Interface Builder - change the separator to None and then the separator color to clear color:
Setting UITableView separatorColor at viewDidLoad might be too early. Try viewWillAppear instead.
I am using FontLabel in the view cells of the table.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
FontLabel *author_name = [[FontLabel alloc] initWithFrame:CGRectMake(58, 10, 217, 16) fontName:#"MyriadPro-Bold" pointSize:12.0f];
author_name.numberOfLines = 1;
author_name.text = [dummyArray objectAtIndex:indexPath.row];
author_name.textColor = [UIColor colorWithRed:0.580 green:0.776 blue:0.329 alpha:1.000];
author_name.backgroundColor = [UIColor clearColor];
[cell addSubview:author_name];
return cell;
}
But the label is loaded multiple times. I can see that it is getting bolder and bolder. How can I fix it?
When you call addSubview, it's not removing the old view. remember that cells are reused so the view you added in the last iteration is still there.
You should instead subclass UITableViewCell so that you can add a UILabel to it.
Edit:
Or you can do
author_name.tag = 10;
and then
FontLabel *author_name = (FontLabel *)[cell.contentView viewWithTag:10];
when you want to retrieve it.