I have a subclassed custom UITableViewCell, in which I am inserting a progress view in it.
here is how:
-(void)layoutSubviews {
applicationDelegate = [[UIApplication sharedApplication] delegate];
[super layoutSubviews];
self.imageView.frame = CGRectMake(0, 0, self.frame.size.height, self.frame.size.height);
self.textLabel.frame = CGRectMake( self.imageView.frame.size.width + 20, self.textLabel.frame.origin.y, self.textLabel.frame.size.width, self.textLabel.frame.size.height);
progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
progressView.frame = CGRectMake(self.textLabel.frame.origin.x, 50, 150, 100);
progressView.progress = 0.0f;
progressView.trackTintColor = [UIColor clearColor];
progressView.progressTintColor = [UIColor redColor];
progressView.tag = 101;
[progressView setHidden:YES];
[self.contentView addSubview:progressView];
}
Now when in other view controller I want to show this elements only in first cell, so I am trying to hide these elements in other cells. Here is how I am trying to do this in cellForRowAtIndexPath: method:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString * cellIdentifier = #"cellId";
CustomCell * cell = [self.tableview dequeueReusableHeaderFooterViewWithIdentifier:cellIdentifier];
if (cell == Nil) {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
if (indexPath.row == 0) {
imageData = UIImageJPEGRepresentation(cell.imageView.image, 100);
filename = cell.textLabel.text;
[(UIProgressView*)[cell.contentView viewWithTag:101] setHidden:NO];<==Not Working
}
return cell;
}
How to use this UIElements in custom UITableView subclass in my ViewController ?
I have not used xib file, everything is done programmatically. I have beed playing around this for whole day now, any one with any idea here ?
If only the 1st row needs to show the progress view, why not only use the custom cell for row 0 and then use a standard UITableViewCell for rows >1?
I would also recommend adding progressView to self.contentView in an init method and not in layoutSubviews. layoutSubviews is intended to position the views you already have (not add new ones) because it can be called many times over the lifetime of the cell.
I would add a BOOL property to the custom cell that determines if you should show the progress indicator (and removes it when set to NO). In cellForRowAtIndexPath: you could set it appropriately for the given row.
In CustomCell.h:
#property(nonatomic, assign) BOOL shouldShowProgressView;
In CustomCell.m:
- (void)setShouldShowProgressView:shouldShowProgressView {
_shouldShowProgressView = shouldShowProgressView;
if (shouldShowProgressView) {
if (self.someProgressView == nil) {
// add your progress view from scratch
}
[self.contentView addSubview:self.someProgressView];
} else {
[self.someProgressView removeFromSuperview];
}
}
In your table controller:
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
static NSString *cellIdentifier = #"cellId";
CustomCell *cell = [self.tableview dequeueReusableHeaderFooterViewWithIdentifier:cellIdentifier];
if (cell == Nil) {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
if (indexPath.row == 0) {
cell.shouldShowProgressView = YES;
} else {
cell.shouldShowProgressView = NO;
}
return cell;
}
Related
Edit:
Thanks everyone, but this has gotten to be too general as it is clear there are deeper issues at hand. I'm going to try to delete this question. I appreciate all of your help!
We have a large UITableViewCell with a UILabel inside and we want to detect the user's single tap or touch on that label. We're adding a UITapGestureRecognizer inside of our subclassed UITableViewCell:
CGRect frame = CGRectMake(0, 10, 150, 20);
self.titleLabel = [[UILabel alloc] initWithFrame:frame];
self.titleLabel.text = self.title;
self.titleLabel.userInteractionEnabled = YES;
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(expandButtonTapped:)];
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;
[self.titleLabel addGestureRecognizer:singleTap];
[cell.contentView addSubview:self.titleLabel];
We've also tried setting the target to the cell's UITableViewController, but same result, the action doesn't get performed. When checking the debugger, the gesture is indeed there and attached to the label.
Edit: After more investigating, if we add a normal UIButton to the cell, it cannot be clicked. Doing more investigating, but here is the cellForRowAtIndexPath method:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (![self.metaDataSections count]) {
return nil;
}
ACMTableCellMetaData *metaData = [self metaDataForIndexPath:indexPath];
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:metaData.reuseIdentifier];
if (cell == nil) {
cell = [metaData createCell];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
cell = [metaData updateCellWithCellForReuse:cell];
return cell;
}
The createCell method:
- (UITableViewCell *)createCell
{
UITableViewCell *cell = [super createCell];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:self.reuseIdentifier];
cell.frame = CGRectMake(CGRectGetMinX(cell.contentView.frame),
CGRectGetMinY(cell.contentView.frame),
CGRectGetWidth(cell.contentView.frame),
ACM_TABLE_CELL_HEIGHT);
[self setupExpandButtonInCell:cell];
}
return cell;
}
updateCell method:
- (UITableViewCell *)updateCellWithCellForReuse:(UITableViewCell *)cell {
UILabel * titleLabel = (UILabel *)[cell.contentView viewWithTag:TITLE_TAG];
titleLabel = self.titleLabel;
self.cell = [super updateCellWithCellForReuse:cell];
return self.cell;
}
I clipped out some code that I don't believe affects anything. The didSelectRowAtIndexPath that is being over ridden in the the subclassed tableview doesn't have anything that would prevent user taps. But strangely, if I put a break point there, it never gets hit when tapping the cells. So I believe there are other issues at play here. We can't see why this is the case however.
If you are writing this code in class, which inherits UITableViewCell, then instead of
[cell.contentView addSubview:self.titleLabel];
use
[self addSubView:self.titleLabel];
make sure to implement
-(void)expandButtonTapped:(parameter type)parameter{
}
in the same class.
I forgot to mention about
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
TableCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!cell)
{
cell = [[TableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
}
// Configure the cell...
return cell;
}
I have created a UITextField in a UITableView. I type the data in and close the keyboard. However when I scroll down and hide the UITextField and then scroll back up again, the 'UITextField' data is duplicated as seen below:
Original Load of View:
Typed in Data:
After hidden textfield and then started editing again:
- (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];
}
if ([indexPath section] == 0) { // Email & Password Section
cell.textLabel.text = #"Subject";
} else {
cell.textLabel.text = #"Task";
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
if ([indexPath section] == 0) {
UITextField *subject = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
subject.adjustsFontSizeToFitWidth = YES;
subject.textColor = [UIColor blackColor];
if ([indexPath row] == 0) {
subject.placeholder = #"Maths";
subject.keyboardType = UIKeyboardTypeEmailAddress;
subject.returnKeyType = UIReturnKeyNext;
}
subject.backgroundColor = [UIColor clearColor];
subject.autocorrectionType = UITextAutocorrectionTypeNo;
subject.autocapitalizationType = UITextAutocapitalizationTypeWords;
subject.tag = 0;
subject.clearButtonMode = UITextFieldViewModeNever;
[cell.contentView addSubview:subject];
} else {
UITextView *task = [[UITextView alloc] initWithFrame:CGRectMake(102, 0, 185, 40)];
task.text = #"fasfashfjasfhasfasdjhasgdgasdhjagshjdgashjdgahjsdghjasgasdashgdgjasd";
task.editable = NO;
task.scrollEnabled = NO;
task.userInteractionEnabled = NO;
task.textColor = [UIColor colorWithRed: 62.0/255.0 green: 85.0/255.0 blue:132.0/255.0 alpha:1.0];
task.backgroundColor = [UIColor clearColor];
}
return cell;
}
Like Richard said, cells are reused (that's what the identifier purpose is), and that's why you test in your tableView:cellForRowAtIndexPath: for a nil value returned by dequeueReusableCellWithIdentifier:.
If a cell already exists (ie. was allocated earlier) and is not displayed anymore, dequeueReusableCellWithIdentifier: will use this cell to display the content of the newly appearing cell.
What you are doing is adding your UITextView every time your cells are displayed and not created. So each time a cell is gets scrolled out of the screen and a new cell pops in, you append a new UITextView in the cell. You should add subviews only in the if (cell == nil) part of your method. As the content of your cells are rather different, I'd recommend using two distinct identifiers.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifierForSection0 = #"Cell0";
static NSString *CellIdentifierForSection1 = #"Cell1";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: [indexPath section] == 0 ? CellIdentifierForSection0 : CellIdentifierForSection1];
if (cell == nil) {
if ([indexPath section] == 0) { // Email & Password Section
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifierForSection0];
cell.textLabel.text = #"Subject";
UITextField *subject = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
subject.adjustsFontSizeToFitWidth = YES;
subject.textColor = [UIColor blackColor];
if ([indexPath row] == 0) {
subject.placeholder = #"Maths";
subject.keyboardType = UIKeyboardTypeEmailAddress;
subject.returnKeyType = UIReturnKeyNext;
}
subject.backgroundColor = [UIColor clearColor];
subject.autocorrectionType = UITextAutocorrectionTypeNo;
subject.autocapitalizationType = UITextAutocapitalizationTypeWords;
subject.tag = 0;
subject.clearButtonMode = UITextFieldViewModeNever;
[cell.contentView addSubview:subject];
} else {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifierForSection1];
cell.textLabel.text = #"Task";
UITextView *task = [[UITextView alloc] initWithFrame:CGRectMake(102, 0, 185, 40)];
task.text = #"fasfashfjasfhasfasdjhasgdgasdhjagshjdgashjdgahjsdghjasgasdashgdgjasd";
task.editable = NO;
task.scrollEnabled = NO;
task.userInteractionEnabled = NO;
task.textColor = [UIColor colorWithRed: 62.0/255.0 green: 85.0/255.0 blue:132.0/255.0 alpha:1.0];
task.backgroundColor = [UIColor clearColor];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
return cell;
}
Note that this code is mainly for example purpose, and could be greatly reducted. Moreover, you should use subclass(es) of UITableViewCell like Richard suggested, as it will help organizing your code and make it more reusable.
BUT do NOT use drawRect: to add subviews. This is unnecessary and will impact performances. drawRect: should only be used if you intend to make real drawing like with CoreAnimation or CoreGraphics. Adding subview should be done in initWithFrame: or initWithCoder: depending of your use of Interface Builder or not.
Remember cells get reused, therefore the subviews are added each time it's reused. If you're going to add subviews to a cell you're best off creating a subclass of UITableViewCell and adding the subviews in the drawRect: method of that subclass. That way the modifications are part of the cell and aren't added each time the cell is reused.
I need to load some data in a table view and while this is going on in the background I want to add an activity indicator in order to show that there is a process going on and will hide once the process finishes. What would be the most efficient way to implement something like this?
Depends, whether you want to block your user or not and also how important is the activity indication.
If you don't want to block user, use Application.networkActivityIndicatorVisible, if you want to have larger activity indicator and still not to block user, animate UIView with text and UIActivityIndicator below the table view (tableview.height -= activityview.height) and then hide on complete or if you would like to block user, use blocking activity indicator.
http://www.dejal.com/developer/?q=developer/dsactivityview
https://github.com/jdg/MBProgressHUD (I was using MBProgressHUD personally and it's easy to learn and use)
You can add a view which has a UIIndicatorView and a UILabel as your cell's subview. You can use this way to show error data loading/ error network/ empty data...
Example:
Your Controller can define two modes: UITableViewModeMessage and UITableViewModeData.
In viewDidLoad, you set self.tableViewMode = UITableViewModeMessage. When has returned data, set self.tableViewMode = UITableViewModeData and reload data for tableview.
Some code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (self.tableViewMode == UITableViewModeMessage) {
return 2;
} else {
return self.yourEntries ? self.yourEntries.count : 0;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (self.tableViewMode == UITableViewModeMessage) {
return [self tableView:tableView messageCellForRowAtIndexPath:indexPath];
} else {
return [self tableView:tableView dataCellForRowAtIndexPath:indexPath];
}
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
// Remove Loading... progress view if exist.
UIView *progressView = [cell viewWithTag:100];
[progressView removeFromSuperview];
if (self.tableViewMode == UITableViewModeMessage) {
if (indexPath.row == 1) {
// remove the current label.
cell.textLabel.text = nil;
// We build progress view and attach to cell here but not in cellForRowAtIndexPath is because in this method cell frame is already calculated.
UIView *progressView = [self progressViewForCell:cell message:#"Loading..." alpha:0.9];
[cell addSubview:progressView];
}
}
}
// cell to display when loading
- (UITableViewCell *)tableView:(UITableView *)tableView messageCellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MessageCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.textLabel.textColor = [UIColor grayColor];
cell.textLabel.textAlignment = UITextAlignmentCenter;
}
if (indexPath.row == 1) {
cell.textLabel.text = #"Loading...";
} else {
cell.textLabel.text = nil;
}
return cell;
}
// cell to display when has data
- (UITableViewCell *)tableView:(UITableView *)tableView dataCellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"DataCell";
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [[self.yourEntries objectAtIndex:indexPath.row] description];
return cell;
}
// Build a view which has a UIActivityIndicatorView and a UILabel
- (UIView *)progressViewForCell:(UITableViewCell *)cell message:(NSString *)message alpha:(CGFloat)alpha
{
// NOTE: progressView needs to be removed from cell in cellForRowAtIndexPath:
CGRect progressViewFrame = CGRectZero;
progressViewFrame.size.width = CGRectGetMaxX(cell.bounds);
progressViewFrame.size.height = CGRectGetMaxY(cell.bounds) - 2;
UIView *progressView = [[UIView alloc] initWithFrame:progressViewFrame];
progressView.backgroundColor = RGBA(255, 255, 255, 1);
progressView.alpha = alpha;
progressView.tag = 100;
UILabel *loadingLabel = [[UILabel alloc] initWithFrame:progressView.bounds];
loadingLabel.backgroundColor = [UIColor clearColor];
loadingLabel.font = [UIFont systemFontOfSize:14];
loadingLabel.textColor = [UIColor blackColor];
loadingLabel.textAlignment = UITextAlignmentCenter;
loadingLabel.text = message;
CGFloat widthOfText = [loadingLabel.text sizeWithFont:loadingLabel.font].width;
CGFloat spaceBetweenIndicatorAndLabel = 5;
// activityIndicatorView has size in which width and height is equal to 20.
UIActivityIndicatorView *activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[activityIndicatorView setCenter:CGPointMake(CGRectGetMidX(cell.bounds) - (widthOfText / 2) - (activityIndicatorView.bounds.size.width / 2) - spaceBetweenIndicatorAndLabel, CGRectGetMidY(cell.bounds))];
[activityIndicatorView setColor:[UIColor blackColor]];
[activityIndicatorView startAnimating];
[progressView addSubview:activityIndicatorView];
[progressView addSubview:loadingLabel];
return progressView;
}
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
I have a table view with five cells displaying the settings of my app. I want the first four cells to appear at the top. The last cell isn't actually a setting, it says "Legal" and takes you to the EULA, so I want it to appear at the bottom.
Now I know I could use – tableView:viewForHeaderInSection: and– tableView:heightForHeaderInSection: to create some padding, but I really don't like hardcoding in dimensions this way. I also don't want to use UIButton, because I want it to be exactly the same style as the rest of the cells.
Does anyone know the best practice for going about this?
I'm assuming you're using a grouped table view, like the settings app. What I've done is created a group section between the top and bottom group sections, to which I've add a 'transparent' row cell, that I size dynamically.
I've created a simple demo for you using hardcoded values, but hopefully you'll get the idea. Obviously you would get the number of sections and the number of rows from your data structure:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
int rtn = 0;
if (section == 0)
rtn = 4;
else if (section == 1)
rtn = 1;
else if (section == 2)
rtn = 1;
return rtn;
}
/*
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 44.0f;
}
*/
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
int TOTALCELLS = 6;
float CONSTANT = 0.5f;
if (indexPath.section == 1)
return self.view.frame.size.height - (44.0f * (CONSTANT + TOTALCELLS));
return 44.0f;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
}
if (indexPath.section == 0)
{
if (indexPath.row == 0) {
cell.textLabel.text = #"My Switch";
UISwitch *boolSwitch = [[UISwitch alloc]initWithFrame:CGRectZero];
boolSwitch.on = YES;
[cell setAccessoryView:boolSwitch];
[boolSwitch release];
} else if (indexPath.row == 1) {
cell.textLabel.text = #"My TxtField";
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
UITextField *txtField = [[UITextField alloc]initWithFrame:CGRectMake(0,0,175,20)];
txtField.text = #"Default Value";
txtField.textColor = [UIColor darkGrayColor];
[txtField setClearButtonMode:UITextFieldViewModeAlways];
[cell setAccessoryView:txtField];
[txtField release];
} else if (indexPath.row == 2) {
cell.selectionStyle=UITableViewCellSelectionStyleNone;
UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(0,0,280,22)];
slider.minimumValue = 0.0f;
slider.maximumValue = 10.0f;
slider.value = 0.7f;
slider.minimumValueImage = [UIImage imageNamed:#"minus.png"];
slider.maximumValueImage = [UIImage imageNamed:#"plus.png"];
[cell setAccessoryView:slider];
[slider addTarget:self action:#selector(sliderChange:forEvent:) forControlEvents:UIControlEventValueChanged];
[slider release];
} else if (indexPath.row == 3) {
cell.textLabel.text = #"My MultiValue";
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.detailTextLabel.text = #"Default selection";
}
} else if (indexPath.section == 1) {
UIView *transCell = [[UIView alloc] initWithFrame:CGRectZero];
transCell.backgroundColor = [UIColor clearColor];
cell.backgroundView = transCell;
[transCell release];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
} else if (indexPath.section == 2) {
cell.textLabel.text = #"Legal";
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
return cell;
}
The critical parts are in cellForRowAtIndexPath, where the transparent row is created. The trick here is to add the transparent view to the cell's backgroundView, and set the cell selection style to None.
UIView *transCell = [[UIView alloc] initWithFrame:CGRectZero];
transCell.backgroundColor = [UIColor clearColor];
cell.backgroundView = transCell;
[transCell release];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
and in heightForRowAtIndexPath, the dynamic sizing of the transparent row.
self.view.frame.size.height - (44.0f * (CONSTANT + TOTALCELLS));
TOTALCELLS is the total of all of the cells, including the transparent one. You may need to do additional work on this algorithm, as it doesn't take into consideration what happens when number of cells grows beyond what is visible, and I haven't tested it with various combinations of navigation and toolbars.
I hope this works for you.