Cell width always return 320, once reload the table then it returns proper cell width based on device(iphone/ipad).Below is the code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *reuseIdentifier = #"testCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if(cell == nil)
{
cell = [[UITableViewCellalloc] initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:reuseIdentifier];
}
cell.textLabel.text = #"test";
return cell;
}
probably it's because in first time your cell will be created via
[[UITableViewCellalloc] initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:reuseIdentifier];
but after reload table your cell will be reused via
[tableView dequeueReusableCellWithIdentifier:reuseIdentifier]
with "old" sizes.
To avoid this, use correct cell identifier in Interface builder, in this case you can even remove creating cell code
[[UITableViewCellalloc] initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:reuseIdentifier]
cell will be always generated from interface
Related
I have this little doubt about reusing UITableViewCell.
When we create UITableViewCell it kinda looks like following.
- (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];
[self configureCell:cell forIndexPath:indexPath];
}
}
- (void)configureCell:(UITableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.section) {/**Cell Config Code Goes Here**/}
}
So in my case, every cell in UITableView is different. And if UITableView reuses the cell the cell content is completely different.
Is it good practice to just pass CellIdentifier as nil so every time new cell is created instead given the condition that all cells are different ?
Or should I just move [self configureCell:cell forIndexPath:indexPath]; out and handle it on by my own ?
Cell reusability has its sense if you are using cell contents(same subviews) multiple time. Like you have two lables in your tableViewcell for all rows in your tableView. If you have small number of different cells. like if you have three types of cells to use multiple times in your tableView, you can use cell reusability with 3 different cell identifier.
But if you have all different cell, then its fine if you skip cell reusability.
The proper way of using reusability of the tableView is shown below.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier = #"FollowerCell";
UITableViewCell *cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell =[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
[self configureCell:cell forIndexPath:indexPath];
return cell;
}
- (void)configureCell:(UITableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.section) {/**Cell Config Code Goes Here**/}
}
The basic idea of reusability is that every time the similar type of cell should not be created, instead they should be reused just by updating their content.
What happens behind the scene is that there is a queue created in which these similar cells are added. Now Suppose there are 200 rows with different data but only 10 rows are visible. That in the queue only approx 14 cells will be present. Now as you will scroll the tableview up or down, this condition
UITableViewCell *cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
checks wether the queue contains any cell, if yes a cell is fetched from the queue. Also the cells, which were earlier visible now on disappearing are added into the queue. This way everytime instead of new cells are created, the already created cells are used.
Now if you forcely make the cell = nil, than every time new cells will be created and added in the queue. Now if there are 200 data than queue will be containing 200 cells thus resulting in increase in memory size.
Hope it will help you in understanding the tableView. Happy Coding :)
I am afraid you have to move the configure cell code out of if condition to make every cell has its own content.
- (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];
}
[self configureCell:cell forIndexPath:indexPath];
}
While we saying reuse of UITableViewCells, we mean that we don't have to create the UIView hierarchy inside the cell every time. But you need to configure the content for different cells. Like cell.titleLabel.text = xxxx.
Meanwhile, you can use multiple reuseIdentifiers for different kind of cells. Or if you only have one such cell, you can define a cell as an attribute instance so that you don't have to create it everytime.
I have a UITableView that display a program name and the DJ name. For some programmes, there are no any DJs. So I created a custom UITableViewCell by putting 2 UILabels. Middle of the UITableViewCell displays the programme name and bottom UILabel displays the DJ name. To display both programme and the DJ name I have to set the cell size and UITableViewCell size as 147. But when DJ is not available I want to hide that bottom label and resize the cell and row height to 70. so how should I do this ?
I am checking if this DJ is null or not inside my cellForRowAtIndexPath method.
How I can resize the cell, and row height ?
Thanks for the help.
You need to use the following delegate:
-(CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*) indexPath {
if(...){
return 147.0f; //or whatever
}
else{
return 70.f;
}
}
Add NSIndexPath below #implementation
NSIndexPath *selectedCellIndexPath;
Add Both of these methods.
// And in the implementation file:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
selectedCellIndexPath = indexPath;
// Forces the table view to call heightForRowAtIndexPath
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// Note: Some operations like calling [tableView cellForRowAtIndexPath:indexPath]
// will call heightForRow and thus create a stack overflow
if(selectedCellIndexPath != nil
&& [selectedCellIndexPath compare:indexPath] == NSOrderedSame)
return 338;
return 64;
}
You have 2 types of cell. With height of 147 and 70 pixels.
1) As Anoop Vaidya said you should set cell height by checking "DJ is null or not".
2) To avoid reusing wrong cell template, you should use 2 types of cellIdentifier:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier = nil;
if (check DJ is nil or not) {
CellIdentifier = #"CellWithHeight_147";
} else {
CellIdentifier = #"CellWithHeight_70";
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
}
...
return cell;
}
I have a customized UITableViewCell and I've added a UIImageView to it. The thing is, there are times when I want to remove the UIImageView as the data I receive from the server does not have an image associated with it. How do I make the cell layout change such that the other elements move up. Should I set the UIImageView's frame to zero? Using a placeholder image is not a solution.
Here's what my problem looks like:
The row with index 0 does not have an image but there is a space in between the top and the bottom label. Is there a way I can do this using Auto Layout?
Your problem is actually caused by heightForRowAtIndexPath, you have to return the proper value in this method, something like:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
YourCustomObject *object = [tableDataSource objectAtIndex:indexPath.row];
if(object.hasImage) {
return heightForCellWithImageInside;
}
else {
return heightForCellWithoutImageInside;
}
}
Then, in your cellForRowAtIndexPath just hide the UIImageView if there is no image for it.
You can dynamically change the height of cell.If there is an image,then increase cell height otherwise not.Also set the imageView whenever u get image from server otherwise no need to set imageView.like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"ImageCellItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
if(imageFromserver)
{
//Set your imageView here
}
else
{
// Do nothing
}
return cell;
}
when ever there is no image coming from server hide or remove your image view and assign the frame of image view to your bottom label.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] ;
}
if(yourimage==nil)
{
bottomlabel.frame=imageview.frame; // you can do something like this, as per your need.this is just example
}
return cell;
I have a text array backing a TableView in iOS. In the cellForRowAtIndexPath: method I return a UITableViewCell* which is populated with text from the backing array. indexPath is used as the index into the backing array.
I now want to add a "Done" button to the last cell in the TableView. In my StoryBoard I've created a second (prototype) TableView Cell and gave it the identifier "ButtonCell". I've also added an extra element to the end of the backing array so numberOfRowsInSection: can return the count of the backing array and everything will just work.
I thought I would set the text of the last array element to something like #"donebutton" and then I could check for that in cellForRowAtIndexPath:. If it comes up true, I would know I'm at the end of my array and to return the "ButtonCell" cell instead of the normal "Cell". Thing is, it's not quite working right. What's the best way to accomplish this? Code snip is below.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
static NSString *ButtonCellIdentifier = #"ButtonCell";
UITableViewCell *bcell = [tableView dequeueReusableCellWithIdentifier:ButtonCellIdentifier forIndexPath:indexPath];
NSString *rowtext = [_mArCellData objectAtIndex:indexPath.row];
// return button cell if last item in list
if ([rowtext isEqualToString:[NSString stringWithFormat:#"%d", SUBMIT_BUTTON]])
{
NSLog(#"hit last row, so using button row");
return bcell;
}
cell.textLabel.text = rowtext;
return cell;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
static NSString *ButtonCellIdentifier = #"ButtonCell";
UITableViewCell *cell;
if (indexPath.row != ([_mArCellData count] - 1) { // if not the last row
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// configure cell...
} else { // last row
cell = [tableView dequeueReusableCellWithIdentifier:ButtonCell];
// configure button cell...
}
return cell;
}
I would just change your if statement to:
if ([tableView numberOfRowsInSection:0] == indexPath.row + 1) {
NSLog(#"hit last row, so using button row");
bcell.textLabel.text = rowtext;
return bcell;
}
This is a little more abstracted than your solution and doesn't rely on a property of a cell being set to anything in particular. I like the way #bilobatum put the dequeueReusableCellWithIdentifier: call in the if statement. That should save some memory as well.
EDIT: I also noticed that you are setting cell text, but not bcell text.
i was following this torturial:
http://www.raywenderlich.com/32283/core-graphics-tutorial-lines-rectangles-and-gradients
It covers customization of dynamic table cells, i need to do it with static table cells.
I have given every cell the identifier "Cell", as he does in the tutorial, i then subclassed the table view controller and implemented this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * CellIdentifier = #"Cell";
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// START NEW
if (![cell.backgroundView isKindOfClass:[CostumCellBackground class]]) {
cell.backgroundView = [[CostumCellBackground alloc] init];
}
if (![cell.selectedBackgroundView isKindOfClass:[CostumCellBackground class]]) {
cell.selectedBackgroundView = [[CostumCellBackground alloc] init];
}
// END NEW
cell.textLabel.backgroundColor = [UIColor clearColor]; // NEW
return cell;
}
CostumCellBackground draws the rect.
I am getting the error "UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:
As far as i understand UITableView is looped for every Cell in the storyboard, and it is supposed to return cell.
So, whats going on here and why does the cell return nil, or doesnt return at all ?
The only difference is that they are static tables, and not prototypes.
If you are using Storyboards and iOS6 and your view controller is a UITableViewController, you will always get a cell if your cell identifier is present in your storyboard. Checking for cel == nil is the old way to do it.
Are you sure you have a custom cell in your storyboard with the "Cell" identifier?
Also, use this:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
If you look in the UITableView.h file you will find:
// newer dequeue method guarantees a cell is returned and resized properly, assuming identifier is registered
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);
Where is you create your cell ??
You should add after:
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
such code (or something another initializer):
if (cell == nil) {
cell = [[UITableViewCell alloc] init];
}
Try this at the beginning of your method:
- (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
];
}