iOS: uitableview redraw objects on first cell to bottom cells - ios

i have a uitableview with custom cells.. with normal code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
DDMainCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil)
{
cell = [[DDMainCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
}
the problem is when i select one cell i add progress bar on the cell that download data online.. but when i Scroll down i find that every 10 cells have the same progress bar .. how can i prevent this behavior ?

Try this,
- (void)viewDidLoad
{
[super viewDidLoad];
dataarr=[[NSMutableArray alloc]init];
indexarr=[[NSMutableArray alloc]init];
mytableview=[[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStylePlain];
mytableview.dataSource=self;
mytableview.delegate=self;
[self.view addSubview:mytableview];
for (int i=0; i<30; i++) {
[dataarr addObject:[NSString stringWithFormat:#"%d",i]];
}
// Do any additional setup after loading the view, typically from a nib.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [dataarr count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] ;
}
cell.textLabel.text=[dataarr objectAtIndex:indexPath.row];
UIActivityIndicatorView *act=[[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[act setFrame:CGRectMake(50, 20, 20, 20)];
act.hidden=YES;
[cell.contentView addSubview:act];
cell.selectionStyle=UITableViewCellSelectionStyleNone;
if ([indexarr containsObject:[dataarr objectAtIndex:indexPath.row]])
{
[act startAnimating];
act.hidden=NO;
return cell;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([indexarr containsObject:[dataarr objectAtIndex:indexPath.row]])
{
[mytableview reloadData];
return;
}
[indexarr addObject:[dataarr objectAtIndex:indexPath.row]];
[mytableview reloadData];
}
Make sure, when downloading is complete, then remove this object from indexarr....

That's because your cells are getting reused; UITableView will put off-screen cells into the reusable cell queue, and dequeue them for reuse if the reuseIdentifier matches. You should use some other data structure (e.g. NSArray or NSDictionary) to track which indices/cells have already been tapped. Then, in the method you showed above, regardless of whether the cell was init-ed or dequeued, set the progress bar according to your underlying data structure.

Here your used UITableViewCellIdentifier is reuseIdentifier. Which will work for all Cells are same type. Now your are taking once cell with progress bar. Now it will different from all cells data.
So use one more tableview cell for progress bar, or while reloading table remove the Progress bar which is exists already and add again. for this use tag for progress bar.

Related

Checkmark for UITableView is not selecting to all TableViewCell

Trying to implement the checkmark for UITableView.
Checkmark for UITableView Cell is not selecting to all row, when scroll tableview
its not not enable.
Below is my code which i Implemented.
IndexButton is UIButton Class which added index init.
-(void)selectAllAction:(IndexedButton *)sender{
for (int rowIndex = 0; rowIndex < [array_MedicineList count]; rowIndex++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:rowIndex inSection:0];
UITableViewCell *cell = [tbl_ProductList cellForRowAtIndexPath:indexPath];
IndexedButton *btn_SelectItem = (IndexedButton *)[cell viewWithTag:TAG_SELECTEDITEM];
[btn_SelectItem setBackgroundImage:[UIImage imageNamed:#"checkMark"] forState:UIControlStateNormal];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *productListTableViewCell = #"ProductListTableViewCell";
ProductListTableViewCell *cell = (ProductListTableViewCell *)[tableView dequeueReusableCellWithIdentifier:productListTableViewCell];
if (cell == nil){
cell = [[ProductListTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:productListTableViewCell];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
IndexedButton *btn_SelectItem = [IndexedButton buttonWithType:UIButtonTypeCustom];
btn_SelectItem.frame = CGRectMake(10,52,32,32);
[btn_SelectItem setBackgroundImage:[UIImage imageNamed:#"uncheckMark"] forState:UIControlStateNormal];
[btn_SelectItem addTarget:self action:#selector(selectItemAction:)forControlEvents:UIControlEventTouchUpInside];
btn_SelectItem.index = (int)indexPath.row;
btn_SelectItem.tag = TAG_SELECTEDITEM;
[cell addSubview:btn_SelectItem];
}
IndexedButton *btn_SelectItem = (IndexedButton *)[cell viewWithTag:TAG_SELECTEDITEM];
btn_SelectItem.index = (int)indexPath.row;
cell.backgroundColor = [UIColor clearColor];
return cell;
}
#All
Need suggestion, how to go forward to implement the check mark for tableview.
I would suggest you to use cell with accessory view with UITableViewCellAccessoryCheckmark type to show all cells selected/ few cells selected/ none of the cells selected.
Also, you must keep the state for each cell index within a section, whether it's selected or not as
// keeps info for selected rows in a section in mutable index set as
NSMutableIndexSet *selctedCellsInSection;
// initialize the above set instance
selctedCellsInSection = [[NSMutableIndexSet alloc] init];
//Inside cell for row at index path
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
if ([selctedCellsInSection containsIndex:indexPath.row])
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
else
[cell setAccessoryType:UITableViewCellAccessoryNone];
// customize cell as per your requirements
return cell;
}
You need to hold the information about a cell's checkmark whether it needs to be shown or not in selctedCellsInSection set as -
Use [selctedCellsInSection addIndex:rowToSelect]
// to add cell index on which checkmark needs to be shown
Use [selctedCellsInSection removeIndex:rowToUnselect]
// to add cell index on which checkmark should not be shown
After, customizing the data source selctedCellsInSection(which keeps information about selected/ unselected cell) reload the tableview.
Reloading the table will reflect the selected cells with Cell's Accessory Checkmark.
In your case as you need show check mark on all cell, you can do so as-
-(void)showCheckMarkOnAllCells
{
for (int rowIndex = 0; rowIndex < [array_MedicineList count]; rowIndex++)
{
[selctedCellsInSection addIndex: rowIndex];
}
[tableView reloadData];
}
#interface BRNCategoryViewController ()
{
NSMutableArray *arySelectCategory;
NSMutableArray *aryCategory;
}
- (void) viewDidLoad
{
arySelectCategory=[NSMutableArray new];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return aryCategory.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
BRNCategoryCell *cell=[[BRNCategoryCell alloc]initWithOwner:self];
if ([arySelectCategory containsObject:[aryCategory objectAtIndex:indexPath.row]])
{
cell.imgBoxView.image=[UIImage imageNamed:#"checkMark"];
}
else
{
cell.imgBoxView.image=[UIImage imageNamed:#"uncheckMark"];
}
cell.lblTitle.textColor=Rgb2UIColor(127, 127, 127);
cell.lblTitle.font=[ASCustomClass FontWithSize:20.0];
cell.lblTitle.text=aryCategory[indexPath.row];
cell.backgroundColor=[UIColor clearColor];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if ([arySelectCategory containsObject:[aryCategory objectAtIndex:indexPath.row]])
{
[arySelectCategory removeObject:[aryCategory objectAtIndex:indexPath.row]];
}
else
{
[arySelectCategory addObject:[aryCategory objectAtIndex:indexPath.row]];
}
[tblEventCategory reloadData];
}

Setting up UITableView methods for reloading data

I have a UITableView that I followed a tutorial on AppCoda, and formatted 2 strings to be displayed in the table that I declared in the ViewController.h. Because my app is parsing a downloaded JSON file, it take a second or two to fill the strings with the variables I want to display. My problem is that it only reloads when the cell reenter the view. What I need to do is reload the methods below when the parsing has finished.
Here are my ViewController.m methods:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [_recipies count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:simpleTableIdentifier];
}
cell.backgroundColor = [UIColor clearColor];
[cell.textLabel setTextColor:[UIColor whiteColor]];
cell.textLabel.text = [_recipies objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [_weatherArray objectAtIndex:indexPath.row];
NSLog(#"Updated");
return cell;
}
Calling [self.tableView reloadData] will reload your table view and call tableview: cellForRowAtIndexPath: as well. (If necessary replace self.tableView with whatever variable you're using to store a reference to your table view.)

UIImage movement on UITableView when selecting cell or scrolling

I feed a UITableView with a list of names and images from a JSON. "SDWebImage" handles images download. It works OK apart from the fact that the images move to the left when the user selects a row or when scrolls the table view.
Two screen captures to show the issue.
Interface Builder setup
Implementation is pretty standard:
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return array.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (cell == nil ) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"Cell"];
}
cell.textLabel.text = [[array objectAtIndex:indexPath.row]objectForKey:#"marca"];
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
[cell.imageView setImageWithURL:[NSURL URLWithString:[[array objectAtIndex:indexPath.row]objectForKey:#"photoUrl"]]placeholderImage:[UIImage imageNamed:#"placeholder.png"] ];
return cell;
}
What can I do to stop images moving?
I've just had a similar issue on an app and found it was because I was re-using UITableViewCells default imageView IBOutlet.
After creating my a new IBOutlet, called something other than imageView, and hooking it up it resolved the issue.

iOS 7 UITableView selects previous IndexPath after scrolling

Ok, so I have this puzzling bug in my app.
I created a TableView dynamically and filled it with some data (the data is not the issue here, empty cells behaves the same). The UITableView displays fine and the data is loaded ok. When i tap the rows in the cell everything is FINE, it selects normally and deselects normally! No worries at all.
Problem:
When I scroll the UITableView it's scrolling normally BUT whenever i try to select a row after scrolling it, the wrong row is selected. The row selected is the one that was pointed at when starting to scroll. It's like the row is getting selected upon touch when you start to scroll and then fires didSelectRowAtIndexPath: when you try to tap on another row in the table. Once the wrong row is selected you can again select the rows you want, until you scroll again!
What could be causing this?
Here's my code for the table view!
//Function to display a summary view after answering all the questions
-(IBAction)displaySummaryView {
viewSummary = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height-60)];
[viewSummary setAlpha:0.0f];
[viewSummary setHidden:YES];
UITableView *tableView = [[UITableView alloc] init];
[tableView setBackgroundColor:[UIColor clearColor]];
[tableView setSeparatorColor:[UIColor colorWithWhite:0.0f alpha:0.25f]];
[tableView setDataSource:self];
[tableView setDelegate:self];
[tableView setTranslatesAutoresizingMaskIntoConstraints:NO]; //Taken care of elsewhere
[viewSummary addSubview:tableView];
//Get all the answers and sort them right!
NSMutableString *predicate = [[NSMutableString alloc] initWithString:#"((SELF.id == '-1')"]; //Init with dummy
for(Answer *ans in activeSession.answers) {
[predicate appendFormat:#" OR (SELF.id == %#)", ans.question_id];
}
[predicate appendFormat:#")"];
summaryQuestionsAndAnswers = nil;
summaryQuestionsAndAnswers = [currentQuestions filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:predicate]];
predicate = nil;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [summaryQuestionsAndAnswers count];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 120.0f;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *cellIdentifier = [NSString stringWithFormat:#"formCell%d",indexPath.row];
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
//Cell creation here
}
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSLog(#"Indexpath section %d row %d", indexPath.section, indexPath.row);
}
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
[cell setBackgroundColor:[UIColor clearColor]];
}
Solved it!
I had a window that logged all touches in the app. This is the function that screwed up my code! Good luck any others encountering this bug. It's usually NOT a reuseIdentifier problem.
if (touch.phase == UITouchPhaseBegan) {
for (UIView *view in views) {
if ( ![view isHidden] && [view pointInside:[touch locationInView:view] withEvent:event] ) {
touchView = view;
[touchView touchesBegan:[event allTouches] withEvent:event];
break; //NOTE: this used to be a return in the previous version
}
}
}

dequeueReusableCellWithIdentifier: Remembering State of Cell

I've embedded horizontal table views inside of table cells (ala the Pulse Reader). The interesting behavior that I'm getting is that dequeueReusableCellWithIdentifier: seems to be correctly remembering the offset of the embedded table views, without me doing anything. But there are two flavors to "remembering"
First (expected)
I create a table with 100 sections and 1 row per section. Each cell (each section) gets an embedded table view that I force to have 100 rows and 1 section. When I scroll the vertical table view, cells are reused (checked by looking at the instance names of the cells after dequeueReusableCellWithIdentifier:
VerticalTableViewCell *cell = (VerticalTableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
If I scroll the first table view cell's embedded table view to the right, say 10.5 cells, when I scroll down a couple cells in the vertical table view, the reused table cell has its embedded table view offset by those 10.5 cells. This makes sense, the cell was just reused and I didn't reset any offsets. Let's say that reused cell was the 7th row. If I now slide the 7th row's embedded table view (this is the same embedded table view as row one, due to the reuse) to position 20, when I go to the top of the vertical table view that embedded table view (which I had originally moved to 10.5), is now at 20. Again, expected, those table cells are the same. Just reused.
Second (desired, but have no idea how it works)
Now I fill in my real data (instead of just printing
[cell.textLabel setText:[NSString stringWithFormat: #"here: %d", indexPath.row]];
to the cell.
Now, all of a sudden, my embedded table views DO remember where they were. I once again ensure the cells are being reused (same method as above). But this time, when I scroll the first embedded table view (to position 10.5) and scroll down to the seventh row, the seventh row is at its starting point. When I scroll the first row back into view, it's right where I left it.
This is using Xcode 4.2 and iOS 5.0. Is there something smart that dequeueReusableCellWithIdentifier: does?
In old school (pre-iOS 5.0), I would have checked the
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
}
bits of logic to see what was happening, but with StoryBoards those are no longer necessary.
The 2 sample projects that behave differently are kind of big, but if there's any relevant code you'd like to see, let me know.
Sorry to be so vague, I'm just trying to grasp exactly whats going on with the memory management of these table views.
All the connections are via IBOutlets and made in the StoryBoard.
Thanks!
First Vertical Table View Controller
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
//#warning Potentially incomplete method implementation.
// Return the number of sections.
return 100;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//#warning Incomplete method implementation.
// Return the number of rows in the section.
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"PlayerCell";
PlayerCell *cell = (PlayerCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
cell.games = [NSMutableArray arrayWithCapacity:1];
if(indexPath.section <40){
//[cell.textLabel setText:[NSString stringWithFormat:#"h343: %d", indexPath.section]];
}
CGAffineTransform rotateTable = CGAffineTransformMakeRotation(-M_PI_2);
cell.htv.transform = rotateTable;
cell.htv.frame = CGRectMake(0, 0, 320, 120);
return cell;
}
First Horizontal Table View Delegate/Data Source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return 100;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
//UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UITableViewCell *cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
CGAffineTransform rotateImage = CGAffineTransformMakeRotation(M_PI_2);
cell.transform = rotateImage;
//[cell.myLabel setText:[NSString stringWithFormat:#"%d", indexPath.row]];
[cell.textLabel setText:[NSString stringWithFormat: #"here: %d", indexPath.row]];
return cell;
}
Second Vertical Table View Controller
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [self.leagues count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"VerticalTableViewCell";
VerticalTableViewCell *cell = (VerticalTableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSLog(#"Cell: %# for index: %d", cell, indexPath.section);
cell.games = [self.leagues objectAtIndex:indexPath.section];
CGAffineTransform rotateTable = CGAffineTransformMakeRotation(-M_PI_2);
cell.horizontalTableView.transform = rotateTable;
cell.horizontalTableView.frame = CGRectMake(0, 0, 320, 120);
// Configure the cell...
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.section = indexPath.section;
return cell;
}
Second Horizontal Table View Delegate/Data Source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.games count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"HorizontalTableViewCell";
//UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
GameTableCell *cell = (GameTableCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
CGAffineTransform rotateImage = CGAffineTransformMakeRotation(M_PI_2);
cell.transform = rotateImage;
//[cell.myLabel setText:[NSString stringWithFormat:#"%d", indexPath.row]];
NSDictionary *game = [self.games objectAtIndex:indexPath.row];
[cell.homeTeamLogo setImage:[UIImage imageNamed:[NSString stringWithFormat:#"%#",[game objectForKey:#"LogoImage_HomeTeam"]]]];
[cell.visitingTeamLogo setImage:[UIImage imageNamed:[NSString stringWithFormat:#"%#",[game objectForKey:#"LogoImage_VisitingTeam"]]]];
[cell.homeTeamName setText:[NSString stringWithFormat:#"%#", [game objectForKey:#"AbbreviatedName_HomeTeam"]]];
[cell.visitingTeamName setText:[NSString stringWithFormat:#"%#", [game objectForKey:#"AbbreviatedName_VisitingTeam"]]];
NSDictionary *gameTime = [game objectForKey:#"GameTime"];
NSString *minutes = [NSString stringWithFormat:#"%#", [gameTime objectForKey:#"Minutes"]];
if([minutes length]==1){
minutes = #"00";
}
NSString *timeOfGame = [NSString stringWithFormat:#"%#:%#",[gameTime objectForKey:#"Hours"], minutes];
[cell.gameTime setText:timeOfGame];
return cell;
}
My fault.
I was saving the state of the the embedded Table View.
FYI: I was using the tableView.contentOffset (in case anybody needs to do this later).
Whoops.

Resources