UITableView's reused cells not getting drawn - objective-c

I have created a tableview with grouped style. I have added this table to the subview of UIScrollView. I have calculated the size of the table according to the number of rows it has. So there is no scrolling for the tableView. I will be able to see all the cells.
For the first time the table works properly and shows all the cells. But my Problem is whenever I navigate to next page and come back and reload that table it is only rendering and redrawing the cells which were allocated. The cells which are getting reused are not getting redrawn. The tableView:cellForRowAtIndexPath: is also not getting called for those cells.
I am suspecting that since the scrolling of the tableview is disabled the cellForRowAtIndexPath method for the reused cells are not getting called and hence they are not getting rendered.
I have created the tableView in the following way
m_TravellerDetailTable = [[UITableView alloc] initWithFrame: CGRectMake( 2.0f, 0, 315.0f, 370 ) style: UITableViewStyleGrouped ];
float height = (tableViewCellHeight * [travellersArray count]);
m_TravellerDetailTable.frame = CGRectMake(2, 0, 315, height);
[m_TravellerDetailTable setBounces: NO];
[m_TravellerDetailTable setScrollEnabled: NO];
[m_BaseScrollView addSubview: m_TravellerDetailTable];
UITableViewDelegate Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [travellersArray count];
}
-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return tableViewCellHeight;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[TravellerDetailCustomCellView alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
TravellerDetailCustomCellView *customCell = (TravellerDetailCustomCellView *)cell;
[customCell.textLabel setText:[travellerInfoFromDetailForm objectForKey:#"DOB"]];
}
This snapshot shows the uitableview rendering all the cells
The Snapshot shows the uitableview rendering only upto "Adult 8" cell. After that the table is not rendering the remaining cells.

it is rendering, but your frame is to small and the table view is cut off.
You should remove
[m_TravellerDetailTable setBounces: NO];
[m_TravellerDetailTable setScrollEnabled: NO];

it's caused by UIScrollView.The UIScrollView cached the drawing of it's subviews. I advice you dont add UITableView to UIScrollView

Related

ipad add tableview (only a part) to viewcontroller with storyboard

So I'm trying to add a UITableView on the lower half of my ipad app which will be used to display a search result. This is how I did it.
I added a UIView
I added a UItableView onto the UIView
I then dragged the UITableView to the ViewController so it can connect to it for delegate and datasource.
This is what it currently looks like:
(It's at that middle top row)
So I added the following onto the viewcontroller class to generate the data
# pragma mark TableView properties
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 2;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"SearchResultCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = #"test";
}
The debugger would go through all these but would get stuck after the "cellForRowAtIndexPath" method:
It would just go through that and would not end until I stop the whole debugging. Not really sure what's going on.
Thoughts? Maybe you guys can point me to the right direction as to how I should generate my search results.
Thanks!
I usually find it much more faster and easier to use the free Sensible TableView framework to do automatic table view searches, instead of using the regular datasource/delegate system which I could never get right.

Storyboard - static cell in Detail view - managing buttons dynamically

I've recently found a way to solve displaying a button when data exists and not when no data is in a cell. Specifically using Storyboards in a detail view (static cell). This button is a necessity on the Storyboard due to some seque wiring I've hooked up.
I placed a custom button with no background image on it, and set a tag value of the tableviewcell to 1.
Then in my implementation file I've overridden the cellForRowAtIndexPath.
My question is, while this works fine, is it performance intensive? I have only 5 cells in this MOC. Here's my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
// need to capture the section and the cell to modify....
if (cell.tag == 1){
if (self.map){
self.mapButton.enabled = YES;
self.mapLabel.text = #"Click Map for Pic Location...";
UIImage *buttonImage = [UIImage imageNamed:#"MyMap.png"];
[self.mapButton setBackgroundImage:buttonImage forState:UIControlStateNormal];
} else{
self.mapLabel.text = #"No Location found for Pic";
self.mapButton.enabled = NO;
}
}
return cell;
}

UITableViewCell with Checkmark not visible

I've a problem with my UITableView inside PopoverController.
When I touch cell, the didSelectRowAtIndexPath function is called, and the cell accessoryType is changed. Example simplified :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self.listItems objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.tableView reloadData];
[self.popoverController dismissPopoverAnimated:YES];
}
It's working, the cell are checked, but it's not visible on my tableview : I can't see the blue checkmark. However, in touch state on the cell, the checkmark is visible in white (and the cell background is gray). But not visible in default state.
Do you have any idea why my checkmark are not visible in default state ?
Thanks,
Edit: Add screenshot, for a cell with accessoryType = UITableViewCellAccessoryCheckmark
This happened to me when I changed the global tint color to white. Once I realized, I went into the UITableView and change the tint color locally for just this table. Fixed.
I've tried the answer Jacky Boy - didn't help. But something was there in the deselection...
So I've tried to deselect the cell in the didSelectRowAtIndexPath: before adding the checkmark accessory:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
UITableViewCell* selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if (row != _selectedRow) {
if (selectedCell.accessoryType == UITableViewCellAccessoryNone) {
selectedCell.accessoryType = UITableViewCellAccessoryCheckmark;
_selectedRow = row;
} else if (selectedCell.accessoryType == UITableViewCellAccessoryCheckmark) {
selectedCell.accessoryType = UITableViewCellAccessoryNone;
}
[tableView reloadData];
}
}
And for me it worked at last - the nice dark checkmark now is clearly visible on the cell!
Of course there is a part in cellForRowAtIndexPath: similar to described in arexx's answer.
I had a similar problem where, after reloading the row with a checkmark set as the accessory, the checkmark wouldn't be visible (but would be visible in white when the row was selected). In testing around the problem I discovered that the checkmark is always present in the cell, it's just white-on-white.
My understanding of the problem is that when I ask for the cell to be reloaded (so that I can show it with a checkmark), the existing cell is put on the reuse queue, but is at that time in a selected state (because the user just selected it). It's still in a selected state when the cell comes back off the reuse queue and you re-configure it in tableView:cellForRowAtIndexPath, and because it's selected, the accessory is set in white instead of in a visible colour.
To fix this, I added a line in tableView:cellForRowAtIndexPath to force the cell not to be selected. The accessory is now always visible when the new cell is displayed.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Get a reusable cell - this only works with Storyboard prototype cells
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyCell"];
// THE MAGIC BIT
// Force the cell to not be in a selected state.
cell.selected = NO;
// END MAGIC BIT
if (indexPathIsPathOfSelectedRow) {
// This is the selected cell, so show the checkmark accessory.
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
// In case we're reusing a cell that previously showed a checkmark, clear it.
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
Mine was the most stupidest reason. I had created a tableview in storyboard, with a View Controller of size 5.5 inch and forgot to apply the layout constraints.
Then I launched in a 4 inch phone, Everything looked fine except the accessory view was not visible because of tableviews width was greater than that of the phone screen. It took me 3 hours to find out my mistake.
You are reloading the UITableView so in theory the cells are recreated and this time without the checkmark. Do the following:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self.listItems objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.popoverController dismissPopoverAnimated:YES];
}
Running under iOS 6.1, the behavior I see is a cell with a white check mark on an almost white background. This appears to be happening because the code that draws the check mark accessory believes the cell is in a highlighted state, so rather than drawing the check mark in the normal blue color, it is drawn in white.
Setting the selected state of the cell did not work for me but setting the highlighted state immediately before setting the accessory type did. With the following in place, I always get a dark blue check mark.
cell.highlighted = NO;
if (checked)
self.accessoryType = UITableViewCellAccessoryCheckmark;
else
self.accessoryType = UITableViewCellAccessoryNone;
If you want to reload Data then you should store selected Id in some variable for single selection like rowIndex and then in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//check index
if (rowIndex==indexPath.row)
{cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else{
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
Thanks.
-(UIImageView *)checkmarkImg{
UIImage *image = [[UIImage imageNamed:#"ic_check_black_24dp.png"] changeColor:CLR_BUY];
UIImageView *checkmark = [[UIImageView alloc] initWithImage:image];
return checkmark;
}
cell.accessoryView = [self checkmarkImg];

Bad EXC_BAD_ACCESS when scrolling through UITableView

I initiated a UITableView with the following code:
ProductTableView *tableProd = [[ProductTableView alloc]initWithNibName:#"ProductTableView" bundle:nil];
the xib file does exist!
Since I am displaying this table in a separate UIView I add it to this screen by:
[content addSubview:tableProd.view];
I used xcode to create a standard UITableView and set the following functions:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 10;
}
- (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];
}
cell.textLabel.text = #"test";
return cell;
}
The table is displayed in the simulator with 10 rows filled with test. However, when I start scrolling, and the first cell leaves the screen, the simulator crashes with a EXC_BAD_ACCESS error. I tried using Instruments to detect the NSZombie and the software flaged the zombie. Unfortunately I cant trace this error back to the cause.
Does anyone have a idea what is going wrong here?
if you're adding the view of a view controller as a subview of another view controllers view, i would guess that the ProductTableView view controller is being dealloced (since adding as a subview retains the view, but not the view controller it belongs to)
add the ProductTableView view controller as a property of the container view controller so that it is retained

Add editing elements to UITableViewCell

I have a couple of rows in a table view which I like to edit.
I thought that setEditing method would give me a Edit and Delete button, but it only shows a Delete button. Because I don't have a detail view controller that's going to be pushed in didSelectRowAtIndexPath I thought I could show a couple of editing elements in the selected cell.
I need to add three buttons to specify priority on assignments: Low, High and Medium priority. This means that I have to change the height of the selected cell to make room for these buttons, I think that's rather easy to do.
What I'm wondering is if this is the correct path to choose?
I have done quite a lot research today without finding examples of how other have solved editing in a UITableViewCell. If you edit a contact in the Contacts app in the iPhone the UITableViewCells changes to enable quick and easy editing, that's what I'm looking for.
So what do you have for tips for me regarding this question?
Edit #1
My code in didSelectRowAtIndexPath is:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Cell *selectedCell = (Cell *)[tableView cellForRowAtIndexPath: indexPath];
UIButton *btn = [UIButton buttonWithType: UIButtonTypeRoundedRect];
btn.frame = CGRectMake(0, 0, 50, 100);
btn.titleLabel.text = #"Set this item to High Priority";
btn.backgroundColor = [UIColor greenColor];
[selectedCell.contentView addSubview: btn];
self.editing = YES;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject: indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
Code for heightForRowAtIndexPath:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
Cell *cell = nil;
if (self.editing)
cell = (Cell *)[tableView cellForRowAtIndexPath: indexPath];
else
cell = nil;
BOOL expandCell = NO;
NSInteger expandationHeight = 0;
if (cell != nil)
{
for (UIButton *btn in cell.contentView.subviews)
{
NSLog(#"A button was found.");
expandationHeight = 70;
expandCell = YES;
}
}
return expandationHeight + heightOfOtherElements;
}
When I click at a cell nothing happends but everything becomes disabled, I can't click any elements on the hole view. This has something to do with [tableView cellForRowAtIndexPath: indexPath], because if I uncomment that line the UI does not become disabled.
What am I doing wrong?
That's not too complicated though it requires some stuff.
You want to change the content of one cell or of all cells?
To specify a specific height for one cell, use the - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath delegate method.
It is called for each cell each time the table view is displayed. If you want to change a single row, call reloadRowsAtIndexPaths:withRowAnimation: method from UITableView. If you want to update all cells, simply use - (void)reloadData method.
You can also access a specific cell using - (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath method from UITableView. Then you can reconfigure it to add various elements on it, as you want.
Thus, when a cell is selected, check whether you have to edit it or not, then :
update your cell get from cellForRowAtIndexPath
be sure your method tableView:heightForRowAtIndexPath: will return the good height
tell the table view to update the view using reloadRowsAtIndexPaths:withRowAnimation: