Create grid table view in iphone - iphone

I want to make a table view in which i want to show some items or images ( 4 items in a row)For eg: If i have 7 images i want to show 4 in first row and 3 in next row and if i have 13 images then it should display like 4,4,4,1 in rows 1,2,3,4 respectively. I have achievd this but my problem is those images keep changing their position (shift from 1 to 3 row and vice versa) when i scroll the table view. Please tell me some way so that my images automatically adjust themselves 4 in a row and does not repeat if i scroll the table view.
My code is:
(array has 7 image-datas stored in it)
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 93;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [array count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Avi"];
for (UIView *view in cell.contentView.subviews) {
[view removeFromSuperview];
}
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Avi"] autorelease];
cell.backgroundColor = [UIColor clearColor];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
NSData *imageData;
for(int i=0;i<4;i++){
imageData=[array objectAtIndex:indexpath.row];
UIButton *Button = [UIButton buttonWithType:UIButtonTypeCustom];
Button.frame = CGRectMake(5+(i*77), 5, 77,85);
[Button setBackgroundImage:[UIImage imageWithData:imageData] forState:UIControlStateNormal];
[cell.contentView addSubview:Button];
}
return cell;

So the code snippet you've posted isn't particularly helpful, but this almost certainly is a case of not recycling your table view cells properly.
Table views 'recycle' their cells for efficiency and performance - when a cell scrolls out of view it is marked for recycling: when you next request a new cell you will be given a recycled cell if one is available (otherwise a new cell will be created).
If all your cells use the same layout, this isn't a problem. However, if you adjust the layout of your cells (as you do) this can cause problems, because you might have set up a cell for 2-picture layout and have it be recycled for a 4-picture cell.
You have two options here: either take care to reset your cells as required (when you request a new cell reset all the view parameters you've created, which in your case would be by removing all the superviews), or create different cells with different identifiers for each of your layouts.
By the way, just looking at your current code it seems like you may want to consider some custom cells. Currently you add new images to the cell's contents view, which means since you never remove them every time your cell gets recycled more and more and more images get added! It's quite inefficient. Better to create a cell that has four image views ready to go, and you just assign the image property as required.

Related

UITableview Reusability issue when drawing a line on tableview cell and moving it to the end of the table

I have to make an application where I can add N number of rows in UITableview.This is how I am using reusability.
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MyCell";
UITableViewCell *Cell=[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(Cell==nil)
{
Cell=[self tableViewCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath ofTableView:tableView];
}
[Cell setSelectionStyle:UITableViewCellEditingStyleNone];
[Cell setAccessoryType:UITableViewCellAccessoryNone];
[self ConfigureCell:Cell forIndexPath:indexPath forTableView:tableView];
return Cell;
}
Then on swipe right I have to draw a line and add button on a particular cell of UITableview that I am doing in swipe gesture method after retrieving the UITableviewCell in that method and have to move cell to the bottom after adding the subviews.
CGPoint location = [recognizer locationInView:GroupedTableView];
NSIndexPath *IndexPath = [GroupedTableView indexPathForRowAtPoint:location];
UITableViewCell *cell = [self.GroupedTableView cellForRowAtIndexPath:IndexPath];
UIButton *CrossButton=[UIButton buttonWithType:UIButtonTypeRoundedRect];
CrossButton.frame=CGRectMake(250, 12, 15, 15);
[CrossButton setBackgroundImage:[UIImage imageNamed:#"x.png"] forState:UIControlStateNormal];
CrossButton.tag=800+IndexPath.row;
[CrossButton addTarget:self action:#selector(CrossButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:CrossButton];
UIImageView *LineImage=[[UIImageView alloc]init];
LineImage.frame=CGRectMake(10, 19, 220, 2);
LineImage.tag=700+IndexPath.row;
LineImage.image=[UIImage imageNamed:#"line.png"];
LineImage.userInteractionEnabled=YES;
[cell.contentView addSubview:LineImage];
NSIndexPath *lastIndexPath = [NSIndexPath indexPathForRow:RowNum inSection:0];
[self.GroupTableContentArray insertObject:[self.GroupTableContentArray objectAtIndex:IndexPath.row] atIndex:lastIndexPath.row+1];
[self.GroupTableContentArray removeObjectAtIndex:IndexPath.row];
[self.GroupedTableView moveRowAtIndexPath:IndexPath toIndexPath:lastIndexPath];
This also works fine till the table height is small but once it is bigger than the screen size and I scroll to see the bottom content,the line I have drawn on that particular cell vanishes and sometimes its visible on other cell which was not marked.I know this is the issue of reusability but I am unable to figure out a way.
My requirement is like any.Do app where we swipe right to select a finished task and put it at the bottom of the table.Any help would be highly appreciated.
It seems to me that you don't quite understand how table view cell reuse works.
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
Asks the table delegate for a cell that is going to be displayed at the specified index path. You ask the table view for a reusable cell with dequeueReusableCellWithIdentifier:. Now, if the returned cell is nil it is your job to create a new cell.
When setting cell properties like text, detail text and image, you have to treat each cell as if it has unwanted data, meaning that you should overwrite everything each time before returning a cell.
To give you an example of this, imagine you have a table view with 10 visible cells and a 100 rows. Your first cell has "Hello world" in it and the other ones are empty. Now, when you start scrolling you are going to be seeing "Hello world" every 10 or so cells. This is happening because a random available cell is being returned from the tables reusable cell queue which has kept all of its changes like text, images, and subviews.
And that is also what is happening to your cell with the line and the button, so to avoid this, appropriate properties should be set for each index path. The problem is that you are adding subviews to your cell with no reference to them so they cannot be removed or hidden easily and so are always visible at random index paths. Furthermore you're going to get in a situation where you have multiple lines and buttons in the same cell.
It would be best for you to create a UITableViewCell subclass where each cell has its own line and button which can be shown/hidden as necessary for each index path.

one image or thumbnail for cells in a table view

i have the following code which will displays result in a UItable view along with an image.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//create a cell
UITableViewCell *cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"cell"];
// fill it with contnets
NSDictionary *exercise = [exercises objectAtIndex:indexPath.row];
cell.textLabel.text = [exercise valueForKey:#"player"];
UIImage *image = [UIImage imageNamed:#"iphone.gif"];
cell.imageView.image = image;
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
// return it
return cell;
}
is there an option where i can display one image for all the cells for ex. 1 image on the left side and then 3 rows by the right side. I am a new bid and still getting my grip on iPhone coding.Please suggest me how we can do this.Thanks.
Yup, a UITableViewCell is pretty much another UIView, so you can add subviews to it and customize it anyway you need. For example, if you need to add an image to all the cells, just add it onto the contentView;
[cell.contentView addSubview:myImageView];
If you have several customizations needed for your cell, and are looking for a highly custom look as opposed to the generic look provided by the standard cells, I'd recommend looking into creating a custom UITableViewCell. The reason is that the standard cells have already laid out UI's with labels, images etc, and anything you add onto it may interfere with the existing UI in ways you do not intend.

Image at 0 index overtake

I've got this nasty problem. My class, which is subclassing UITableViewController, has a method which is invoking
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
The method which is invoking what is above is this one:
- (void) insertInfo:(UIImage *)image
{
self.hotelImage = nil;
self.hotelImage = image;
numRows = numRows + 1;
[self.tableView beginUpdates];
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
}
This is how I am creating a cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
self.datacell = nil;
self.datacell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"SimpleTableIdentifier"] autorelease];
self.myImageView = nil;
self.myImageView = [[UIImageView alloc] initWithImage:self.hotelImage];
[self.myImageView setFrame:CGRectMake(5, 5, 80, 75)];
[self.datacell.contentView addSubview:self.myImageView];
[self.myImageView release];
self.tableView.userInteractionEnabled = YES;
self.tableView.separatorColor = [UIColor clearColor];
return self.datacell;
}
So, my problem is that when I scroll the table, all images in the table get replaced by a single image at index 0. My guess is that it has something to do with the fact that when cell is created, every image in the section is considered at index 0, but different image is shown when table is created. But when the table is scrolled by user, different images get overtaken by an image the is in the index 0 of the first cell.
This is exactly what happens, the image on the first cell is shown on all cells when the table begins to scroll.
I just don't know how to make every cell retain its unique image when the table is scrolled. My guess is it has something to do with placing image indexPath.section??? But I am not sure. Could somebody please help me with this problem?
Thank you,
Victor.
Effectively you're editing the contents of your table with insertInfo, but not editing its actual source, so as soon as it needs to redraw those cells, they get reverted to its original source. Try using something along the lines of:
self.myImageView=[[UIImageView alloc] initWithImage:[myImageArray objectAtIndex:indexPath.row]];
The fact is that the tableView doesn't keep your cells around. As soon as you scroll them out of view they are gone, released, deallocated as far as you know, and the table view asks the data soucre for new replacement cells. Your cellForRowAtIndexPath is always returning the same cell, independent of what the table view asks for.
You should be storing the images sent to insertInfo into an array, then in cellForRowAtIndexPath, always return the image from the array by index, looked up by indexPath.row and indexPath.section. Every time you scroll, that cellForRowAtIndexPath is called to get all the new cells that weren't on screen, this is why the cells always "change to" the most recent image sent to insertInfo.
Try adding a new file to your project, subclass of UITableViewController, and check out the default code there. You'll find dequeueReusableCellWithIdentifier is also a useful one.
The key concept here is that cellForRowAtIndexPath: is a question, and your code needs to check the values of indexPath.section and indexPath.row, and return a value that belongs to that row/section.

Button placement on table footer view

I have a table view wherein the number cells are not fixed and will keep on changing. I have to show two action buttons after my last cell in the table footer. How can I place them properly after my last cell? I know the pixel spacing between last cell and these buttons. Any code sample will be really helpful.
Have you tried sticking them in a view and setting that as the footer view?
You need to give it the correct height before you add it; the width is automatically set to the width of the table. Either set it to a sensible width (e.g. 320) and use autoresizing or use a custom UIView subclass and implement -layoutSubviews.
You could always add two buttons to the final cell.
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section {
return [myCellDataArray count]+1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
if (indexPath.row > [myCellDataArray count]) {
cell = [tableView dequeueReusableCellWithIdentifier:#"Button Cell"];
if (cell == nil) {
UIButton *firstButton = [[UIButton alloc] init];
//customization
UIButton *secondButton = [[UIButton alloc] init];
//customization
[cell addSubView:firstButton];
[cell addSubView:firstButton];
}
} else {
// normal stuff
}
If you want to customize existing buttons you need to set it's tag to something unique, i.e. firstButton.tag = 100 and then set firstButton by firstButton = (UIButton *)[cell viewWithTag:100];. Make sure you define firstButton so that it's in scope!
Hope this helps!

UITableViewCell and strange behaviour in grouped UITableView

I'm working on a grouped UITableView, with 4 sections with one row per section, and have a strange behaviour with the cells.
The cells are plain UITableViewCells, but the height of the cells are around 60 - 80 pixel.
Now the tableview renders the cells correct with round corners, but when I select the cells, they appear blue and rectangle. I don't know why the cells behave like this, because I have another grouped UITableView with custom cells and 88 pixel height and those cells work like they should.
If I change the height to the default height of 44 pixel, the cells behave like the should. Does anyone know about this behaviour and what the cause is?
Like I mentioned, I don't do any fancy stuff I use default UITableViewCells in a static, grouped UITableView with 4 sections with 1 row in each section.
evangelion2100
Edit: OK, here are the relevant parts of my code. Because I only use a fixed number of cells for this tableview I store the cells in a 2d NSMutableArray. I set up the cells in the -(void)viewDidLoad method and the respective delegate Methods access the Array with the stored cells.
I don't see anything that would cause this strange behaviour of the cells if they get selected.
Edit2: Sorry the reason why I store the cells in an array is not only the among of cells. If the view changes and UITableView reappears, the cells will be exchanged with custom cells. That the real reason for the storage of the cells. It's like some kind of "add new email"-Type of behaviour, like in the contact app from the iphone.
-(void)viewDidLoad {
// set up the AccompanyingLecture cell
UITableViewCell *accompanyingLectureCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"AccompanyingLectureCell"];
accompanyingLectureCell.textLabel.textAlignment = UITextAlignmentCenter;
accompanyingLectureCell.detailTextLabel.textAlignment = UITextAlignmentCenter;
accompanyingLectureCell.textLabel.text = NSLocalizedString(#"New Accompanying Lecture", #"");
accompanyingLectureCell.detailTextLabel.text = NSLocalizedString(#"Lecturer, Time, Location, etc.", #"");
accompanyingLectureCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
accompanyingLectureCell.frame = CGRectMake(0, 0, 320, 82);
// initialize datasource for all four sections
datasource = [[NSMutableArray alloc] initWithObjects:[NSMutableArray arrayWithObject:[lecturerCell autorelease]], [NSMutableArray arrayWithObject:[lectureDetailsCell autorelease]], [NSMutableArray arrayWithObject:[timeAndLocationCell autorelease]], [NSMutableArray arrayWithObject:[accompanyingLectureCell autorelease]], nil];
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
return [[datasource objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
}
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGRect currentFrame = [[[datasource objectAtIndex: indexPath.section] objectAtIndex:indexPath.row] frame];
return currentFrame.size.height;
}
What happens if you simply return 82 in the heightForRowAtIndexPath method and don't set the cell's frame in viewDidLoad?