I have an odd bug, after use tap row cell's image changed. I didn't implement didSelectRowAtIndexPath method, so i guess its just table reloading forces image to redraw.
Here is code:
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// Загружаем ячейку из класса, далее подгружаем текст из класса initialData.
MyCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
NewsParseer *news = [self.objectsArray objectAtIndex:indexPath.row];
// Text
cell.textLabel.text = news.text;
// Image
[cell.imageView setImageWithURL:news.urlImage];
return cell;
}
Very simple. Here is screenshots, first - when app launched and load image. Second, when i tap a row.
Obviously i don't want image to resize after user interaction.
For anyone that wondered whats going wrong, there is answer:
I tried to set image to default property of cell, called imageView, but in Storyboard and in my custom class i work with different image view (property that i call myImageView).
Related
I need UITableViewCell in a dynamic height depends on the content length.
This is a prototype cell
And the content shows fine when first loaded like this
But when I scroll the UITableView, the cell's content breaks like this, especially for UIImageView.
In the implementation of the cell, I only used setImage and setText method.
What seems the problem? Or, is there another way to set each cell's height differently after viewDidLoad?
** Edit: this is my implementation of cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NotificationCell *cell = [tableView dequeueReusableCellWithIdentifier:#"notification"];
if(!cell) {
[tableView registerNib:[UINib nibWithNibName:#"NotificationCell" bundle:nil] forCellReuseIdentifier:#"notification"];
cell = [tableView dequeueReusableCellWithIdentifier:#"notification"];
}
[cell setContent:[notifications objectAtIndex:indexPath.row]];
[cell layoutIfNeeded];
return cell;
}
And setContent in NotificationCell.m has only setText and setImage
Because the tableView already has an imageView property and it is on the left side of the cell, you set the image to that imageView. You should rename the outlet of your custom imageView. So, it should be not called imageView, give the other name for it.
Here is my code :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier=#"menucell";
MenuCell *cell = (MenuCell*) [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
if (cell==nil)
cell= [[MenuCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] ;
MenuModel *resturntent = (self.menuList)[indexPath.row];
cell.foodNameLbl.text = resturntent.MenuName;
cell.priceLbl.text = [NSString stringWithFormat:#"%# %#",#"$" , resturntent.MenuRate];
cell.foodImage.image = [UIImage imageNamed:#"full_breakfast.jpg"];
return cell;
}
While scrolling uitextfields values gets duplicates .
I need help to fix this issues
When you use dequeueReusableCellWithIdentifier, your cells will be reused. This means when the user scrolls the tableview, a cell which moves out of the screen will be reused to display the contents of a cell which is about to move onto the screen.
Even though this helps in saving memory, the problem it causes is the that the cell needs to be prepared for display before it is loaded with the content of the new cell.
In your case, it seems you need to maintain the values the user has entered in a textfield of a cell.
So to fix your problem, if there are not that many cells in the tableview, simply stop reusing the cell. Else whenever the user enters a value in the textfield of a cell, save it in an array (array of 'MenuModel' in your case). And fetch the value from from the model and set it to your textfield in the cellForRowAtIndexPath method like your have set values for other labels.
So basically what I am doing now is expanding my cells by selecting on them and using heightForRowAtIndexPath to change their height and if I select on it again or select a different cell those cells will expand or go back to their normal size.
However, upon the cell expanding I have some extra data to show in the expanded section, change the background color of the cell and set some other properties that I have defined in my tableviewcell subclass. So as an example when the cell is in its normal height the background will be light green. When its expanded it needs to be white. I set my tableviewcell subclass property (a BOOL) so that when its time to loop through the cells again (cellforRowatindexpath) i can update these properties as needed. Unfortunately, I haven't been able to find a way to get the current cell thats been selected in cellForRowAtIndexPath.
Here is the relevant code below. Keep in mind that I want to keep track of the current cell selected and the previous cell (if different from the current one) so that i can update both cells properties. Only one cell can be expanded at a time. When the current cell is selected and expanded the previous one(if applicable) will contract back to normal height. My configureCell method is just there to assign the properties based its BOOL property.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:myIdentifier forIndexPath:indexPath];
[cell configureCell:self.item[indexPath.row] isCollapsed:cell.isCollapsed];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
MyCustomCell *currentCell;
MyCustomCell *previousCell;
self.currentSelectedIndex = indexPath;
//assign previous and current if previous is nil
if(!self.previousSelectedIndex){
self.previousSelectedIndex = self.currentSelectedIndex;
currentCell = [tableView cellForRowAtIndexPath:self.currentSelectedIndex];
currentCell.isCollapsed = NO;
}
//we have tapped the same cell as before
else if(self.previousSelectedIndex == self.currentSelectedIndex){
previousCell = [tableView cellForRowAtIndexPath:self.previousSelectedIndex];
previousCell.isCollapsed = YES;
self.previousSelectedIndex = self.currentSelectedIndex = nil;
}
//if they aren't equal, then collapse the previous selected cell
//and expand the current selected cell
else{
previousCell = [tableView cellForRowAtIndexPath:self.previousSelectedIndex];
previousCell.isCollapsed = YES;
currentCell = [tableView cellForRowAtIndexPath:self.currentSelectedIndex];
currentCell.isCollapsed = NO;
self.previousSelectedIndex = self.currentSelectedIndex;
}
[tableView beginUpdates];
if(self.currentSelectedIndex){
[tableView reloadRowsAtIndexPaths:#[self.currentSelectedIndex, self.previousSelectedIndex] withRowAnimation:UITableViewRowAnimationAutomatic];
}
[tableView endUpdates];
}
So, obviously my current and previous cell will be trashed once we leave this method since they are local but I am struggling with how to:
a. reload the cells which would cause cellForRowAtIndexPath to execute again(this works when trying to use reloadRows - but maybe I'm doing that wrong)
b.once cellForRowAtIndex starts going through the cells how to capture the currentCell and the previousCell so that i can update its content as I described above. [dequeueReusableCellWithIdentifier:myIdentifier] just gets a new cell which I do not want obviously.
The cells expand and contract fine so thats not an issue.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MyCell";
MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil)
cell = [[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
Movie *movie = [self.movies objectAtIndex:indexPath.row];
cell.title.text = movie.title;
cell.subtitle.text = movie.subtitle;
cell.subtitle.numberOfLines = 0;
[cell.subtitle sizeToFit];
return cell;
}
I am calling reloadData from two places. One is from the end of a loadInitialData function, which is called from viewDidLoad.
A second one is being called from viewDidAppear, although this is inconsequential to my problem, because it existed before it and exists without it.
I initially load 3 rows of sample data, with titles and subtitles. Now what happens is my subtitle text is vertically centered when this window first launches. If I grab the table and scroll is high up, all of a sudden my [cell.subtitle sizeToFit] goes into action, and my text goes to the top vertically, which is desired.
So my issue is... why is the text vertically centered from the beginning? reloadData doesn't work either. When I return from adding a new row, all rows but the newly added row are vertically aligned to top as they should. The new row is incorrectly vertically centered.
Why doesn't this work? Everything seems good. New data is added etc. Via NSLog statements, I have verified numberOfRowsInSection is immediately called after reloadData is called.
So why does the aligning of the text vertically to the top not work?
Thanks!
This is probably because the UITableViewCell has not yet been layed out and so it does not have a size yet. Try doing the sizeToFit in this UITableViewDelegate method
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
I am not sure this will work, but it worth trying.
Add [cell setNeedsLayout]; before you return the cell so it will layout the cell before presentation.
When I push a UIViewController onto my UINavigation controller like:
[(UINavigationController *)self.parentViewController pushViewController:[[[Fonts alloc] initWithNibName:#"Fonts" bundle:nil] autorelease] animated:YES];
Where Fonts.xib is a UIView with only UITableView controlled by a Fonts object that is a subclass of UIViewController and acts as the UITableView's dataSource and delegate.
In the Fonts object I create a UITableViewCell like:
- (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: #"BlahTableViewCell"];
if (!cell) {
cell = [[UITableViewCell alloc]
initWithStyle: UITableViewCellStyleDefault
reuseIdentifier: #"BlahTableViewCell"];
[cell autorelease]; // Delete for ARC
}
return cell;
}
And then I change the font of the cell here:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
[cell.textLabel setFont:[(UIFont *)[self.listOfFonts objectAtIndex:indexPath.row] fontWithSize:cell.textLabel.font.pointSize]];
cell.textLabel.text = [(UIFont *)[self.listOfFonts objectAtIndex:indexPath.row] fontName];
}
listOfFonts is an NSArray of UIFont objects.
When the view appears it looks like UITableView without changed fonts
If I call reloadData on the UITableView or if I drag the UITableViewCells off screen with my finger and let them bounce back they are redrawn and the view the cells display with the labels having their fonts changed.
It seems like the issue is the UITableViewCells are being drawn too early. If I delay the drawing of them everything looks correct but I want the UITableView to be displaying correctly when the UINavigationController slides my view into place.
Any idea what I am doing wrong?
EDIT: I uploaded a simple and straightforward example of my issue to Dropbox. http://dl.dropbox.com/u/5535847/UITableViewIssue.zip
SOLVED IT!
Ok so I was having exactly the same issues as the original poster and this was the problem.
The line that's causing issues is:
[cell.textLabel setFont:[(UIFont *)[self.listOfFonts objectAtIndex:indexPath.row] fontWithSize:cell.textLabel.font.pointSize]];
Specifically, your issue is because you're trying to feed the cell's textLabel its own pointSize, but pointSize doesn't exist yet so strange bugs occur instead. For me, I noticed that a "transform" was failing due to a singular matrix being non-invertible. As soon as I hardcoded a standard value as my pointSize I saw all my labels draw with the proper font instantly. Note: this makes sense as to why a redraw worked, because then your textLabel does indeed have a pointSize.
In any case, you need to explicitly set your pointSize here, no using what the textLabel "already has" because it doesn't have anything until you're "reloading" a cell.
Set the label font inside -tableView:cellForRowAtIndexPath:.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = #"identifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease];
// do it here if your font doesn't change ....
}
// otherwise here with your font ...
cell.textLabel.font = [UIFont boldSystemFontOfSize:12];
return cell;
}
I'm not sure that table cells are designed to be customisable in this way. The table cell may assume that you won't customise the font, and so not draw itself in a way that's compatible with what you are trying to do.
You'd be better off creating a custom table cell, or appending a UILabel as a subview to the table cell when you create it, and them setting the font of that label instead.
It may seem like overkill for such a small customisation, but it's flexible and it's guaranteed to work.