How to make UITableView like above image?
I know this is grouped table type. but how we can add the image+label+button to header of section.
I have tried
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
but it starts with CGRectMake(0,0,320,height).
I want just above section and exact width of section just like in image.
Thanks in advance.
Instead of trying to change the section header view, you might want to create a custom cell with a brown background, a label and a button and use it for the first row. So, in -cellForRowAtIndexPath, you could do something like
if (0 == indexPath.row) {
return brownCell;
} else {
return normalCell;
}
There are several ways to create custom cells, I always start from the Table View Programming Guide for iOS.
CustomCell.h
#import <UIKit/UIKit.h>
#interface CustomCell : UITableViewCell{
id delegate;
NSIndexPath *indexpath;
}
#property(nonatomic,assign) id delegate;
#property(nonatomic,retain)NSIndexPath *indexpath;
#property(nonatomic,retain) IBOutlet UIToolbar *Toolbar;
-(IBAction)SelectorLeft:(id)sender;
-(IBAction)SelectorRight:(id)sender;
#end
customcell.m
#import "CustomCell.h"
#import <QuartzCore/QuartzCore.h>
#implementation CustomCell
#synthesize Toolbar;
#synthesize delegate,indexpath;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
-(IBAction)SelectorLeft:(id)sender{
[delegate perfromselector:#selector(left:) withObject:indexpath];
}
-(IBAction)SelectorRight:(id)sender{
[delegate perfromselector:#selector(left:) withObject:indexpath];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
UItbaleView part
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"identifier";
NSUInteger row = [indexPath row];
if (row == 0) {
CustomCell *cell = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
self.Cell = nil;
[[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
cell = self.Cell;
}
cell.Toolbar.clipsToBounds=YES;
CALayer *l=cell.Toolbar.layer;
// set corner radious
[l setCornerRadius:10];
// to apply border on corners
[l setBorderColor:[[UIColor clearColor] CGColor]];
// to apply set border width.
[l setBorderWidth:5.0];
return cell;
}else{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease];
}
cell.textLabel.text = [NSString stringWithFormat: #"cell %i",row];
cell.delegate = self;
cell.indexpath = indexpath;
return cell;
}
return nil;
}
Also do n't forget to create Customcell.xib and add tool bar through interface builder
also create an outlet of CustomCell in tableview class and handle it as above
its easy all what you have to
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSUInteger row = [indexPath row];
if (row % 2 == 0) {
static NSString *identifier = #"RowOne";
UITableViewCell *cell = (RowTypeOne*)[tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault]autorelease];
}
cell.Title.text = [datasource objectatindex:row];
cell.Title.font = [UIFont fontWithName:#"Tahoma" size:16];
cell.contentView.backgroundColor = [UIColor redColor];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.textAlignment = UITextAlignmentRight;
return cell;
}else if (row % 2 == 1) {
static NSString *identifier = #"RowTwo";
UITableViewCell *cell = (RowTypeOne*)[tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault]autorelease];
}
cell.contentView.backgroundColor = [UIColor redColor];
cell.Title.text = [datasource objectatindex:row];
cell.Title.font = [UIFont fontWithName:#"Tahoma" size:16];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.textAlignment = UITextAlignmentRight;
return cell;
}
return nil;
}
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
//create btn left each on handeled by selector
UIBarButtonItem *btnleft = [[UIBarButtonItem alloc] initWithTitle:#"List of sms" style:UIBarButtonItemStylePlain target:self action:#selector(ListClicked:)];
//create btn right each on handeled by selector
UIBarButtonItem *btnright = [[UIBarButtonItem alloc] initWithTitle:#"New" style:UIBarButtonItemStyleBordered target:self action:#selector(NewClicked:)];
//create uitoolbar then add btns to it as list of array
UIToolbar *tool = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
//change style of toolbar to be black
[tool setBarStyle:UIBarStyleBlack];
tool.items = [NSArray arrayWithObjects:btnleft,[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],btnright, nil];
//this is the parent view that we will add on it the uitoolbar objects and the buttons
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
[view autorelease];
[view addSubview:tool];
return view;
}
-(void)ListClicked:(id)sender{
//handle here btn left
}
-(void)NewClicked:(id)sender{
//handle here btn right
}
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
return 44;
}
if you want the cell not to be in the header you can check for first row in cellforrow at index path...
also if you want to do it in another style you can make custom cell and add it also to cellforrowatindexpath
Related
Can you please help me to do this one?
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = (UITableViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [popOveritem objectAtIndex:indexPath.row];
[cell.textLabel setFont:[UIFont systemFontOfSize:10.05f]];
cell.imageView.image = [UIImage imageNamed:[popimage objectAtIndex:indexPath.row]];
NSLog(#"cellCOntent%#",cell.textLabel.text);
UIView *cellbgColorView = [[[UIView alloc] init]autorelease];
[cellbgColorView setBackgroundColor:[UIColor colorWithRed:40/255.0 green:128/255.0 blue:184/255.0 alpha:1.0]];
cell.selectedBackgroundView = cellbgColorView;
tableVIEW.scrollEnabled = NO;
return cell;
first time the tableview will show one record and when i click to the button appeared in the view will add another row at the top of the table view?
take a look at the below code hope it gives you what you need
viewcontroller.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UIAlertViewDelegate,UITableViewDataSource,UITableViewDelegate>
{
IBOutlet UITableView *tblTest;
NSMutableArray *arrData;
int increment;
}
-(IBAction)onClickAdd:(id)sender;
#end
viewcontroller.m
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
arrData = [[NSMutableArray alloc] initWithObjects:#"Data 1", nil];
increment = 1;
}
-(IBAction)onClickAdd:(id)sender
{
increment++;
NSString *strInsertData = [NSString stringWithFormat:#"Data %d",increment];
[arrData insertObject:strInsertData atIndex:0];
[tblTest reloadData];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [arrData count];
}
-(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:nil];
cell.accessoryView = nil;
cell.selectionStyle = UITableViewCellSelectionStyleGray;
}
cell.textLabel.text = [arrData objectAtIndex:indexPath.row];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
Check Images removing after scrolling.
I have to reuse cell and also dont want to use didselectrow method because i am having several buttons in one cell and this is the sample i created for stackoverflow.
I searched a lot in google and found helpless.
Here Is my Sample Code
//
// TVViewController.h
// tableviewcheck
#import <UIKit/UIKit.h>
#interface TVViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>{
UITableView *sampleTableView;
UIImageView * imageView1;
UIButton* aButton1;
UIImageView *imageViewchk1;
int tag;
}
#property (nonatomic, strong) IBOutlet UITableView *sampleTableView;
#end
// TVViewController.m
// tableviewcheck
#import "TVViewController.h"
#interface TVViewController ()
#end
#implementation TVViewController
#synthesize sampleTableView;
- (void)viewDidLoad
{
[super viewDidLoad];
// 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.
// Usually the number of items in your array (the one that holds your list)
// NSLog(#"selected %i and deliveryArray %i",[queueArray count],[deliveryArray count]);
return 50;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//Where we configure the cell in each row
// NSString *CellIdentifier =[NSString stringWithFormat:#"%i-%i", indexPath.section,indexPath.row];
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell;
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]autorelease];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}
imageViewchk1 = [[UIImageView alloc] initWithFrame:CGRectMake(56,0 , 24,24)];
imageViewchk1.image = [UIImage imageNamed:#"check.png"];
imageViewchk1.tag=indexPath.row+10000;
imageViewchk1.hidden=YES;
imageView1 = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 80,80)];
imageView1.image = [UIImage imageNamed:#"newframe.png"];
aButton1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[aButton1 setTag:indexPath.row];
[aButton1 setImage:imageView1.image forState:UIControlStateNormal];
aButton1.frame = CGRectMake(0, 0, 80,80);
[aButton1 addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[aButton1 addSubview:imageViewchk1];
[cell.contentView addSubview:aButton1];
return cell;
}
-(void)buttonClicked:(UIButton*)sender {
tag = sender.tag;
NSLog(#"buttonClicked %i",tag);
UIImageView *imageView = (UIImageView *)[sampleTableView viewWithTag:tag+10000];
if(imageView.hidden)
{
imageView.hidden=NO;
}
else {
imageView.hidden=YES;
}
}
Well, the problem with you implementation is, that you only set the imageView.hidden property in the buttonClicked method.
When a cell is not shown on the screen for a moment and then shown again, cellForRow is called again.
The problem here is, that you do not store in which cell the imageView.hidden has been set to NO. That is why every time a cell is shown again, the cellForRow: sets its imageView.hidden to YES.
So solution will be to store the numbers of the cell, where imageView.hidden= NO and check in cellForRow if the cell at that indexpath is one where imageView.hidden= NO.
Answering My Own Question For the People searching same Functionality, Here How i did the changes
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
tempArray=[[NSMutableArray alloc] init];
for(int count=0;count<50;count++)
[tempArray addObject:[NSNumber numberWithBool:NO]];
}
- (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.
// Usually the number of items in your array (the one that holds your list)
// NSLog(#"selected %i and deliveryArray %i",[queueArray count],[deliveryArray count]);
return 50;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell;
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]autorelease];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}
imageView1 = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 80,80)];
imageView1.image = [UIImage imageNamed:#"newframe.png"];
imageViewchk1 = [[UIImageView alloc] initWithFrame:CGRectMake(56,0 , 24,24)];
imageViewchk1.image = [UIImage imageNamed:#"check.png"];
imageViewchk1.tag=indexPath.row+10000;
imageViewchk1.hidden=YES;
aButton1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[aButton1 setTag:indexPath.row];
[aButton1 setImage:imageView1.image forState:UIControlStateNormal];
aButton1.frame = CGRectMake(0, 0, 80,80);
[aButton1 addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[aButton1 addSubview:imageViewchk1];
BOOL selected=[[tempArray objectAtIndex:indexPath.row] boolValue];
if(selected)
{
// imageViewchk1.image = [UIImage imageNamed:#"check.png"];
imageViewchk1.hidden=NO;
}
else
{
imageViewchk1.hidden=YES;
}
[cell.contentView addSubview:aButton1];
return cell;
}
-(void)buttonClicked:(UIButton*)sender {
tag = sender.tag;
NSLog(#"buttonClicked %i",tag);
NSIndexPath *index=[sampleTableView indexPathForCell:(UITableViewCell *)[[sender superview] superview]];
BOOL selected=[[tempArray objectAtIndex:index.row] boolValue];
if(selected)
{
[tempArray replaceObjectAtIndex:index.row withObject:[NSNumber numberWithBool:NO]];
}
else
[tempArray replaceObjectAtIndex:index.row withObject:[NSNumber numberWithBool:YES]];
[sampleTableView reloadData];
}
I am trying to implement UITableview based application. In my tableView their is 10 Section and each section having one row.
I want implement each section have Different type of ContentView(1-8 same ContentView 9th section Different ContentView). I did this code For that.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 10;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier1 = #"Cell1";
static NSString *CellIdentifier2 = #"Cell2";
UITextField *textField;
UITextView *textView;
NSUInteger section=[indexPath section];
if(section == 9){
UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];
//UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
if(cell==nil){
cell=[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier1]autorelease];
textView=[[UITextView alloc]initWithFrame:CGRectMake(5, 5, 290, 110)];
[textView setBackgroundColor:[UIColor scrollViewTexturedBackgroundColor
]];
[textView setTag:([indexPath section]+100)];
[cell.contentView addSubview:textView];
}else{
textView=(UITextView*)[cell.contentView viewWithTag:([indexPath section]+100)];
}
return cell;
}else {
UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];
// UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if(cell==nil){
cell=[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier2]autorelease];
textField=[[UITextField alloc]initWithFrame:CGRectMake(5, 5, 290, 50)];
[textField setBackgroundColor:[UIColor scrollViewTexturedBackgroundColor]];
[textField setTag:([indexPath section]+100)];
[cell.contentView addSubview:textField];
}else{
textField=(UITextField*)[cell.contentView viewWithTag:([indexPath section]+100)];
}
return cell;
}
return nil;
}
My problem are:
1. After type some thing in the UITextField/UITextView i am scrolling in the UITableView. that time all data in the UITableViewCell(UITextField/UITextView) was lose, except last cell data.
2. If i create cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Instead of
UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];
Data will repeating . How can i over come this problem?
This line:
UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];
Should never appear in your data source cellForRowAtIndexPath method.
Apart from that, your code is OK, except that you are not setting the text field value anywhere. You need a model (such as an array of strings for the 10 textfield values). This model should be updated when the textfields are edited, and in your method above you copy the value back out of the model and into the textfield's text property:
textfield.text = [self.modelArray objectAtIndex:indexPath.section];
The table pools and reuses cells in an unpredictable fashion, so that subview of a cell that just scrolled off the bottom might reappear next at the top, or might be disposed of.
This is why you saw it partially work. The cell's subviews work okay until their cell gets reused or unloaded, then things move to the wrong place or data disappears.
The solution is that your table's datasource needs to hold onto it's own data. This is usually an array representing your model. Your case is a little unusual because you are using the text controls in your table as inputs, rather than display, which is more typical.
I suggest doing it like this:
// in #interface
#property (nonatomic, retain) NSMutableArray *sections;
// in #implementation
#synthesize sections=_sections;
// at some point before the view appears
self.sections = [NSMutableArray array];
for (int i=0; i<10; i++) {
UIControl *textControl;
if (i<9) {
textControl=[[UITextView alloc]initWithFrame:CGRectMake(5, 5, 290, 110)];
} else {
textControl=[[UITextField alloc]initWithFrame:CGRectMake(5, 5, 290, 50)];
}
[textControl setBackgroundColor:[UIColor scrollViewTexturedBackgroundColor]];
[textControl setTag:i+100];
[sections addObject:textControl];
[textControl release];
}
Now your cellForRowAtIndexPath is a little simpler:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier1 = #"Cell1";
static NSString *CellIdentifier2 = #"Cell2";
NSUInteger section=[indexPath section];
if(section == 9) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
if(cell==nil) {
cell=[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier1]autorelease];
}
} else {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if(cell==nil) {
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier2]autorelease];
}
}
// who knows what subview this cell has? it might not have one, or it might have the wrong one
// just clean it up to be certain
for (UIView *view in cell.subviews) {
[view removeFromSuperView];
}
// get the textControl we set up for _this_ section/cell
UIControl *textControl = [self.sections objectAtIndex:section];
// now we have a fresh cell and the right textControl. drop it in
[cell addSubview:textControl];
return cell;
}
hey the reason is you are doing this things when cell is nil ? but you are not writing any code when cell is not nil.
look at this example , in this example i am adding image view in tableview cell , hence you can add textviews or any other views like this
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UIImageView *imgView;
if(cell == nil)
{
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
imgView = [[UIImageView alloc] initWithFrame:CGRectMake(100,0,100,62)];
[imgView setImage:[UIImage imageNamed:#"img.png"]];
imgView.tag = 55;
[cell.contentView addSubview:imgView];
[imgView release];
}
else
{
imgView = (id)[cell.contentView viewWithTag:55];
}
so as showin here imgView = (id)[cell.contentView viewWithTag:55]; you have to give tag to you and write code showing above in else..
Let you try to make the cell labels and textviews by using following code. It works for me.
if (tagvalue ==3) {
static NSString *CellIdentifier = #"Cell3";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier] autorelease];
}
lbl7 = [[UILabel alloc] init];
[lbl7 setFont:[UIFont boldSystemFontOfSize:20]];
[cell.contentView addSubview:lbl7];
lbl7.backgroundColor = [UIColor clearColor];
lbl7.frame = CGRectMake(120, 5, 0, 40);
lbl7.tag = 70;
[lbl7 release];
lbl8 = [[UILabel alloc] init];
[lbl8 setFont:[UIFont boldSystemFontOfSize:18]];
[cell.contentView addSubview:lbl8];
lbl8.backgroundColor = [UIColor clearColor];
lbl8.textColor = [UIColor grayColor];
lbl8.frame = CGRectMake(120, 50, 0, 40);
lbl8.tag = 80;
[lbl8 release];
lbl7 = (UILabel*)[cell.contentView viewWithTag:70];
lbl8 = (UILabel*)[cell.contentView viewWithTag:80];
lbl7.text = [[rowsarray objectAtIndex:row]objectForKey:#"name"];
lbl8.text = [[rowsarray objectAtIndex:row]objectForKey:#"flavour"];
[lbl7 sizeToFit];
[lbl8 sizeToFit];
return cell;
}
if (tagvalue ==4) {
static NSString *CellIdentifier = #"Cell4";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
lbl9 = [[UILabel alloc] init];
[lbl9 setFont:[UIFont boldSystemFontOfSize:20]];
[cell.contentView addSubview:lbl9];
lbl9.backgroundColor = [UIColor clearColor];
lbl9.frame = CGRectMake(120, 5, 0, 40);
lbl9.tag = 90;
[lbl9 release];
lbl10 = [[UILabel alloc] init];
[lbl10 setFont:[UIFont boldSystemFontOfSize:18]];
[cell.contentView addSubview:lbl10];
lbl10.backgroundColor = [UIColor clearColor];
lbl10.textColor = [UIColor grayColor];
lbl10.frame = CGRectMake(120, 50, 0, 40);
lbl10.tag = 100;
[lbl10 release];
lbl9 = (UILabel*)[cell.contentView viewWithTag:90];
lbl10 = (UILabel*)[cell.contentView viewWithTag:100];
lbl9.text = [[rowsarray objectAtIndex:row]objectForKey:#"name"];
lbl10.text = [[rowsarray objectAtIndex:row]objectForKey:#"flavour"];
[lbl9 sizeToFit];
[lbl10 sizeToFit];
return cell;
}
I had same issue. Its not the problem with table class. The issue is at the place where you are calling this tableviewcontroller. First make the object of this call in .h and then allocate in .m, thats it..
When I was declaring in viewdidload like tbl *t = [self.storyboard...];, I was also facing the same problem. But when I put tbl *t; in .h problem solved.
I am trying create an accordion type of uitableviewcell that, when the user selects the cell, it expands to display a detailed info view inline similar to how the digg app works. I initially tried replacing the current tablecell with a customcell in cellForRowAtIndex, however the animation looks a bit choppy as you can see the cell being replaced and overall the effect doesn't work too well.
If you look at the digg app and others who have done this it seems that they aren't replacing the current cell but instead perhaps adding a subview to the cell? The original cell however doesn't seem to animate at all and only the new view accordions into the table.
Does anyone have any ideas how to accomplish a similar effect?
I have made some progress using neha's method below and while the cell is animating the correct way it is wreaking havoc with the other cells in the table. What I have done is subclassed UITableViewCell with a custom class which contains an instance of a UIView which actually draws the view which I then add to the table cell's contentview.
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
if (selected) {
[self expandCell];
}
}
-(void)expandCell {
self.contentView.frame = CGRectMake(0.0, 0.0, self.contentView.bounds.size.width, 110);
}
Here are all the table delegate methods I am using:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (isSearching && indexPath.row == selectedIndex) {
static NSString *CellIdentifier = #"SearchCell";
CustomTableCell *cell = (CustomTableCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[CustomTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
[cell setCustomTitle:[timeZoneNames objectAtIndex:indexPath.row] detail:[timeZoneNames objectAtIndex:indexPath.row]];
UILabel *theText = [[UILabel alloc] initWithFrame:CGRectMake(10.0, 10.0, cell.contentView.bounds.size.width -20, 22.0)];
theText.text = #"Title Text";
[cell.contentView addSubview:theText];
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(10.0, 10 + 46.0, cell.contentView.bounds.size.width - 20, 40.0)];
textField.borderStyle = UITextBorderStyleLine;
[cell.contentView addSubview:textField];
UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectMake(5.0, 88.0, cell.contentView.bounds.size.width - 20, 22.0)];
testLabel.text = [NSString stringWithFormat:#"Some text here"];
[cell.contentView addSubview:testLabel];
[theText release];
[textField release];
[testLabel release];
return cell;
} else {
static NSString *CellIdentifier = #"Cell";
CustomTableCell *cell = (CustomTableCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[CustomTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
[cell setCustomTitle:[timeZoneNames objectAtIndex:indexPath.row] detail:[timeZoneNames objectAtIndex:indexPath.row]];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
selectedIndex = indexPath.row;
isSearching = YES;
[tableView beginUpdates];
[tableView endUpdates];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (isSearching && indexPath.row == selectedIndex) {
return 110;
}
return rowHeight;
}
It seems now that the cell is expanding but not actually being refreshed so the labels, and textfield aren't being shown. They do however show up when I scroll the cell off and on the screen.
Any ideas?
The Apple way to do is quite simple.
First, you'll need to save the selected indexPath row:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.selectedRowIndex = [indexPath retain];
[tableView beginUpdates];
[tableView endUpdates];
}
I'll explain the begin/end updated part later.
Then, when you have the currently selected index, you can tell the tableView that it should give that row more space.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
//check if the index actually exists
if(selectedRowIndex && indexPath.row == selectedRowIndex.row) {
return 100;
}
return 44;
}
This will return height 100 for the selected cell.
Now we can go back to the begin/end updates. That block triggers the reload of all tableView geometry. Moreover, that block is animated, which eventually gives the impressions of the row expanding.
Pawel's beginUpdates/endUpdates trick is good, and I often use it. But in this case you simply need to reload the rows that are changing state, ensuring that you correctly reload them with the desired cell type, and that you return the correct new cell height.
Here is a complete working implementation of what I think you're trying to accomplish:
.h:
#import <UIKit/UIKit.h>
#interface ExpandingTableViewController : UITableViewController
{
}
#property (retain) NSIndexPath* selectedIndexPath;
#end
.m:
#implementation ExpandingTableViewController
#synthesize selectedIndexPath;
- (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 10;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier1 = #"Cell1";
static NSString *CellIdentifier2 = #"Cell2";
UITableViewCell *cell;
NSIndexPath* indexPathSelected = self.selectedIndexPath;
if ( nil == indexPathSelected || [indexPathSelected compare: indexPath] != NSOrderedSame )
{
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier1] autorelease];
}
cell.textLabel.text = [NSString stringWithFormat: #"cell %d", indexPath.row];
}
else
{
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier2] autorelease];
}
cell.textLabel.text = [NSString stringWithFormat: #"cell %d", indexPath.row];
cell.detailTextLabel.text = [NSString stringWithFormat: #"(expanded!)", indexPath.row];
}
return cell;
}
#pragma mark -
#pragma mark Table view delegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ( self.selectedIndexPath != nil && [self.selectedIndexPath compare: indexPath] == NSOrderedSame )
{
return tableView.rowHeight * 2;
}
return tableView.rowHeight;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray* toReload = [NSArray arrayWithObjects: indexPath, self.selectedIndexPath, nil];
self.selectedIndexPath = indexPath;
[tableView reloadRowsAtIndexPaths: toReload withRowAnimation: UITableViewRowAnimationMiddle];
}
#pragma mark -
#pragma mark Memory management
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
}
- (void)dealloc {
[super dealloc];
}
#end
If you don't want to reload the cell (you want to keep your existing cell and just change the size, and likely add/remove some subviews), then simply do the beginUpdates/endUpdates trick in didSelectRowAtIndexPath:, and call some method on your cell to incite the layout change. beginUpdates/endUpdates will prompt the tableView to re-query the heights for each cell - so be sure to return the correct value.
Create a class that subclasses UITableviewcell in your project. Create this class' nib and set its parent to be the class in your project with tableview and override its -
(void)setSelected:(BOOL)selected animated:(BOOL)animated
Write methods contractCell() and expandCell() in this class, and provide the height of the cells you want in expandCell method. Call this methods appropriately based on some flags set to identify wheather the cell is in expanded state or contracted state. Use your tableview's
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
method to handle selection of cells.
Replace your cellForRowAtIndexPath function with this one.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath {
if (isSearching && indexPath.row == selectedIndex) {
static NSString *CellIdentifier = #"SearchCell";
CustomTableCell *cell = [[[CustomTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
[cell setCustomTitle:[timeZoneNames objectAtIndex:indexPath.row] detail:[timeZoneNames objectAtIndex:indexPath.row]];
UILabel *theText = [[UILabel alloc] initWithFrame:CGRectMake(10.0,
10.0, cell.contentView.bounds.size.width
-20, 22.0)];
theText.text = #"Title Text";
[cell.contentView addSubview:theText];
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(10.0, 10 +
46.0, cell.contentView.bounds.size.width - 20, 40.0)];
textField.borderStyle = UITextBorderStyleLine;
[cell.contentView addSubview:textField];
UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectMake(5.0,
88.0, cell.contentView.bounds.size.width - 20, 22.0)];
testLabel.text = [NSString stringWithFormat:#"Some text here"];
[cell.contentView addSubview:testLabel];
[theText release];
[textField release];
[testLabel release];
return cell;
} else {
static NSString *CellIdentifier = #"Cell";
CustomTableCell *cell = [[[CustomTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
[cell setCustomTitle:[timeZoneNames objectAtIndex:indexPath.row] detail:[timeZoneNames objectAtIndex:indexPath.row]];
return cell;
}
}
create array wof dictionary which have a key Select_sts which is 0 in start when click its change 1
accourding u change table
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
customView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 40.0)];
UILabel * headerLabel = [[UILabel alloc] initWithFrame:CGRectZero];
headerLabel.backgroundColor = [UIColor clearColor];
headerLabel.opaque = NO;
headerLabel.textColor = [UIColor blackColor];
headerLabel.highlightedTextColor = [UIColor whiteColor];
headerLabel.font = [UIFont boldSystemFontOfSize:16];
headerLabel.frame = CGRectMake(5.0, 10.0, 300.0, 20.0);
headerLabel.text=[NSString stringWithFormat: #"PNR %#",[[record objectAtIndex:section] objectForKey:#"number"]];
customView.backgroundColor=[UIColor whiteColor];
btn_openClose.tag=section+10000;
btn_openClose.backgroundColor=[UIColor clearColor];
// [btn_openClose setImage:[UIImage imageNamed:#"down_arrow.png"] forState:UIControlStateNormal];
[btn_openClose addTarget:self action:#selector(collapseExpandButtonTap:) forControlEvents:UIControlEventTouchUpInside];
[customView addSubview:btn_openClose];
}
- (void) collapseExpandButtonTap:(id) sender{
int indexNo=[sender tag]-10000;
// NSLog(#"total_record %#",[total_record objectAtIndex:indexNo]);
NSMutableDictionary *mutDictionary = [[total_record objectAtIndex:indexNo] mutableCopy];
if([[mutDictionary objectForKey:#"Select_sts"] integerValue]==0)
[mutDictionary setObject:[NSNumber numberWithInt:1] forKey:#"√"];
else
[mutDictionary setObject:[NSNumber numberWithInt:0] forKey:#"Select_sts"];
[total_record replaceObjectAtIndex:indexNo withObject:mutDictionary];
// [table_view beginUpdates];
// [table_view reloadData];
// [table_view endUpdates];
NSMutableIndexSet *indetsetToUpdate = [[NSMutableIndexSet alloc]init];
[indetsetToUpdate addIndex:indexNo]; // [indetsetToUpdate addIndex:<#(NSUInteger)#>]
// You can add multiple indexes(sections) here.
[table_view reloadSections:indetsetToUpdate withRowAnimation:UITableViewRowAnimationFade];
}
I am displaying some data using a UITableViewController, my table has 2 static sections with 6 static rows each. And I am subclassing UITableViewCell in order to add 3 Labels and a View, in the view I draw an arrow in only one of the cells in one of the sections.
This all goes perfectly fine. Till i scroll down... then the arrow is randomly placed in other cells, once i scroll back up the arrow has again changed cells... This also happens if i try to set a backgroundColor for only one of the cells. Once I scroll down and up the cell that originally had the color no longer has it, and another seemingly random cell has the color now.
Here is some of my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
TableViewCells *cell = (TableViewCells *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[TableViewCells alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)configureCell:(TableViewCells *)cell atIndexPath:(NSIndexPath *)indexPath {
switch (indexPath.row) {
case 0:
{
if (indexPath.section == cotizacionIdeal)
{
cell.arrowImage = [UIImage imageNamed:#"arrowUp.png"];
[cell.nombre setText:#"Recursos"];
[cell.cantidad setText:[NSString stringWithFormat:#"%1.2f", [cotizacionPrevia.sueldoDeRecursos doubleValue]]];
[cell.porcentaje setText:[NSString stringWithFormat:#"%1.2f%#", [cotizacion.recursosPorcentaje doubleValue], #"%"]];
}
else
{
[cell.nombre setText:#"Recursos"];
[cell.cantidad setText:[NSString stringWithFormat:#"%1.2f", [cotizacionPrevia.sueldoDeRecursos doubleValue]]];
[cell.porcentaje setText:[Calculate calcPorcentaje:cotizacionPrevia.sueldoDeRecursos totalReal:self.totalReal]];
}
}
break;
case 1:
{
if (indexPath.section == cotizacionIdeal)
{
[cell.nombre setText:#"Comision de Venta"];
[cell.cantidad setText:[Calculate calcMonto:cotizacion.comisionPorcentaje total:self.totalIdeal]];
[cell.porcentaje setText:[NSString stringWithFormat:#"%1.2f%#", [cotizacion.comisionPorcentaje doubleValue], #"%"]];
}
else
{
[cell.nombre setText:#"Comision de Venta"];
[cell.cantidad setText:self.montoRealComision];
[cell.porcentaje setText:[NSString stringWithFormat:#"%1.2f%#", [cotizacion.comisionPorcentaje doubleValue], #"%"]];
}
}
UITableViewCell class:
- (id)initWithFrame:(CGRect)frame cell:(TableViewCells *)cell
{
if (self = [super initWithFrame:frame]) {
_cell = cell;
//self.opaque = YES;
//self.backgroundColor = _cell.backgroundColor;
}
return self;
}
- (void)drawRect:(CGRect)rect
{
[_cell.arrowImage drawAtPoint:CGPointMake(0, 0)];
}
#end
#implementation TableViewCells
#synthesize nombre;
#synthesize porcentaje;
#synthesize cantidad;
#synthesize arrowImage;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
// Initialization code
UILabel *nombreLabel = [[UILabel alloc] initWithFrame:CGRectZero];
self.nombre = nombreLabel;
[nombreLabel release];
[self.nombre setFont:[UIFont boldSystemFontOfSize:14]];
[self.contentView addSubview:self.nombre];
UILabel *porcentajeLabel = [[UILabel alloc] initWithFrame:CGRectZero];
self.porcentaje = porcentajeLabel;
[porcentajeLabel release];
[self.porcentaje setFont:[UIFont italicSystemFontOfSize:10]];
[self.contentView addSubview:self.porcentaje];
UILabel *cantidadLabel = [[UILabel alloc] initWithFrame:CGRectZero];
self.cantidad = cantidadLabel;
[self.cantidad setTextAlignment:UITextAlignmentRight];
[cantidadLabel release];
[self.cantidad setFont:[UIFont boldSystemFontOfSize:14]];
[self.contentView addSubview:self.cantidad];
cellContentView = [[TableViewCellContentView alloc] initWithFrame:CGRectZero cell:self];
cellContentView.backgroundColor = [UIColor clearColor];
[self.contentView addSubview:cellContentView];
}
UPDATE:
I have also tried setting the image to a different one for everyone but one and I am still having the same issue.
- (void)configureCell:(TableViewCells *)cell atIndexPath:(NSIndexPath *)indexPath {
cell.arrowImage = [UIImage imageNamed:#"arrowDown.png"];
switch (indexPath.row) {
case 0:
{
if (indexPath.section == cotizacionIdeal)
{
cell.arrowImage = [UIImage imageNamed:#"arrowUp.png"];
[cell.nombre setText:#"Recursos"];
[cell.cantidad setText:[NSString stringWithFormat:#"%1.2f", [cotizacionPrevia.sueldoDeRecursos doubleValue]]];
[cell.porcentaje setText:[NSString stringWithFormat:#"%1.2f%#", [cotizacion.recursosPorcentaje doubleValue], #"%"]];
}
else
{
The problem is that whenever you use drawRect for a cell you MUST call setneedsdisplay. That is what fixed my problem.
The issue is that the UITableView reuses cells so that it doesn't need to make more instances than are displayed and you're not explicitly removing the arrow in your configureCell method.
If the arrow shouldn't be displayed on a cell, explicitly clear it out in the configureCell method and that should fix it.
I am not 100% on this but I think it is to do with the release of the image. When you use imageNamed, the instance is retained so it is suggested to use imageWithFilePath instead.
Hope this helps....