I have a textfield in the MyCustomCell, and set the textfield delegate in the cellForRowIndexPath tableview delegate. When user changes the textfield value and it calls textFieldShouldEndEditing. All it works.
However, I wonder how to know which textfield (indexPath) is changed?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Cell";
MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
// use this if you created your cell with IB
cell = [[[NSBundle mainBundle] loadNibNamed:#"MyCustomCell" owner:self options:nil] objectAtIndex:0];
// otherwise use this
cell = [[[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
// now set the view controller as the text field delegate
cell.textField.delegate = self;
}
// configure cell...
return cell;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
Set UITextField tag in your cellForRowAtIndexPath method. If there is only one section in your tableview you can set the row as tag. Like this.
cell.textField.delegate = self;
cell.textField.tag = indexPath.row;
And in your textFieldShouldEndEditing method you can check the tag.
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
int row = textField.tag;
[textField resignFirstResponder];
return YES;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
if ([[[textField superview] superview] isKindOfClass:[MyCustomCell class]]) {
MyCustomCell *cell = (MyCustomCell *)[[textField superview] superview];
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
// this is what you want.
}
return YES;
}
You Can Try this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Cell";
MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
// use this if you created your cell with IB
cell = [[[NSBundle mainBundle] loadNibNamed:#"MyCustomCell" owner:self options:nil] objectAtIndex:0];
// otherwise use this
cell = [[[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
// now set the view controller as the text field delegate
cell.textField.delegate = self;
textField.tag = indexPath.Row;
}
// configure cell...
return cell;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
NSLog("Selected Cell is:%#",textField.tag);
[textField resignFirstResponder];
return YES;
}
Related
I Have a issue regarding accessing cell label outside of cellForRowAtIndexPath. Firstly in cellForRowAtIndexPath i am hiding cell.lblempName.hidden = YES;
Below is my code :
- (void)viewDidLoad {
[super viewDidLoad];
self.tblemplist.tableFooterView=self.footerView;
}
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
EmployeeCell *cell = (EmployeeCell *) [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"EmployeeCell" owner:self options:nil];
for (id currentObject in topLevelObjects){
if ([currentObject isKindOfClass:[UITableViewCell class]]){
cell = (EmployeeCell *) currentObject;
cell.backgroundColor=[UIColor clearColor];
}
}
}
NSMutableDictionary *detailsdict=[empArray objectAtIndex:indexPath.row];
cell.lblTitle.text = [detailsdict objectForKey:#"empTitle"];
cell.lblItemprice.text = [detailsdict objectForKey:#"empId"];
cell.lblempName.hidden = YES;
}
And in the Footer i have added a View and placed a button. When i click the button lblempName should UnHide.
- (IBAction)btnApplyClicked:(id)sender {
// How to unHide cell.lblempName.hidden = NO;
}
please help me to find the solution. TIA
create a bool property as BOOL isEmpNameHidden;
In viewDidLoad, set isEmpNameHidden = YES;
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Your existing code here
....
cell.lblempName.hidden = isEmpNameHidden;
}
then unhide based on the button tap
- (IBAction)btnApplyClicked:(id)sender {
isEmpNameHidden = NO;
[self.tblemplist reloadData]
}
EmployeeCell *cell = (EmployeeCell *)[self.tableView cellForRowAtIndexPath:indexPath];
UILabel *label = cell.lblempName;
label.hidden = NO;
But better is to modify your data, because as soon as the cell scrolls out of the view and back again the label will be visible again since it will be constructed again.
I have a UITextField for customCell for UITableView.
On TapGesture of UITextField, I need to display checkmark on right side of UITableViewCell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
PreferenceCellWithTextBox *cell = (PreferenceCellWithTextBox *)[tableView dequeueReusableCellWithIdentifier:#"PreferenceCellIdentifier"];
if (cell == nil)
{
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"PreferenceCellWithTextBox"
owner:nil
options:nil];
for (id currentObject in topLevelObjects)
{
if ([currentObject isKindOfClass:[UITableViewCell class]])
{
cell=(PreferenceCellWithTextBox *)currentObject;
break;
}
}
if([self.checkedIndexPath isEqual:indexPath])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
UITapGestureRecognizer *tap=[[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(forwardToDidSelect:)];
[cell.userIdTextField addGestureRecognizer:tap];
}
return cell;
}
Here, I am writing for Tap Gesture. and It gets called only once. It should not happen like that. It should get called whenever I may touch UITextField which is on UITableViewCell.
-(void)forwardToDidSelect:(UITapGestureRecognizer *)tap
{
[self tableView:self.userIdSuggestiontableView didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
}
Here, I have written code for did select row. On Select of any row, I want to display the Checkmark.and remove checkmark from previous one.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(self.checkedIndexPath)
{
PreferenceCellWithTextBox* uncheckCell =(PreferenceCellWithTextBox *) [tableView
cellForRowAtIndexPath:self.checkedIndexPath];
uncheckCell.accessoryType = UITableViewCellAccessoryNone;
}
if([self.checkedIndexPath isEqual:indexPath])
{
self.checkedIndexPath = nil;
}
else
{
PreferenceCellWithTextBox* cell = (PreferenceCellWithTextBox*)[tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
self.checkedIndexPath = indexPath;
}
}
Found The solution with help of #parcs and #payal- This link helped -> http://www.appcoda.com/customize-table-view-cells-for-uitableview/
Basically , the table view lags when i scroll, i have gone through many post but it didn't help-
UITableView in UIScrollview scrolling delay
Delayed UIImageView Rendering in UITableView
slow scrolling of UITableView
UITableView lags while scrolling
This is the code , which i am using in cellForRowIndexpath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"WorkoutCell";
WorkoutCell *cell = (WorkoutCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!cell)
{
UIViewController *controller=[[UIViewController alloc] initWithNibName:CellIdentifier bundle:nil];
cell=(WorkoutCell *)controller.view;
}
[[cell contentView] setBackgroundColor:[UIColor clearColor]];
[[cell backgroundView] setBackgroundColor:[UIColor clearColor]];
[cell setBackgroundColor:[UIColor clearColor]];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
//diplaying Workout Data
[cell setupFont];
cell.lblPoint.text=[NSString stringWithFormat:#"%#",[[arrTblData objectAtIndex:indexPath.row]valueForKey:#"point"]];
cell.lblReps.text=[[arrTblData objectAtIndex:indexPath.row]valueForKey:#"reps"];
cell.lblWorkoutCategory.text=[[arrTblData objectAtIndex:indexPath.row]valueForKey:#"workout"];
cell.lblWeight.text=[[arrTblData objectAtIndex:indexPath.row]valueForKey:#"weight"];
cell.lblSets.text=[[arrTblData objectAtIndex:indexPath.row]valueForKey:#"sets"];
//Formatting Date
cell.lblPostedDate.text=[NSString stringWithFormat:#"Posted On: %#",[self formatDate:[[arrTblData objectAtIndex:indexPath.row]valueForKey:#"time"]]];
return cell;
}
The Function SetupFont called from cellForRowIndexpath
-
(void)setupFont
{
self.lblPoint.font=DEFAULT_FONT(13);
self.pointLblScreen.font=DEFAULT_FONT(13);
self.lblPostedDate.font=DEFAULT_FONT(13);
self.lblReps.font=DEFAULT_FONT(13);
self.lblSets.font=DEFAULT_FONT(13);
self.lblWeight.font=DEFAULT_FONT(13);
self.lblWorkoutCategory.font=DEFAULT_FONT(18);
self.lblWorkoutCategory.strokeColor=kStrokeColor2;
self.lblWorkoutCategory.strokeSize = kStrokeBigSize;
for(UILabel *lbl in [self subviews])
{
if(lbl.tag==9)
{
lbl.font=DEFAULT_FONT(13);
}
}
}
Format Date Function called from cellForRowIndexpath
#pragma mark - Format Date Function
-(NSMutableString*)formatDate:(NSString*)date
{
NSMutableString *formattedDate=[[NSMutableString alloc]init];
NSUInteger p = 0;
NSUInteger length = [date length];
while ( p < length) {
unichar ch = [date characterAtIndex: p];
if (ch!=' ')
{
if(ch=='-')
{
ch='/';
}
NSString *appendString = [NSString stringWithFormat:#"%c",ch];
[formattedDate appendString:appendString];
p++;
}
else
{
break;
}
}
return formattedDate;
}
This is not the right way to do this:
WorkoutCell *cell = (WorkoutCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!cell)
{
UIViewController *controller=[[UIViewController alloc] initWithNibName:CellIdentifier bundle:nil];
cell=(WorkoutCell *)controller.view;
}
Instead of this, subclass UITableViewCell and instantiate that cell here as follows:
WorkoutCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"WorkoutCell" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
}
Also, move your setupFont method the UITableViewCell subclass.
You are typecasting the UIViewController to UITableviewCell.Instead of that take UITableViewCell class add the outlets whatever you want and use it
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CustomCell";
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[NSBundle mainBundle]loadNibNamed:#"CustomCell" owner:nil options:nil] objectAtIndex:0];
}
// access that CustomCell variables here
cell.name.text = #"Name";
}
You use
#interface WorkoutCell : UITableViewCell {}
then table view class
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString * const CellIdentifier = #"WorkoutCell";
WorkoutCell *cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier];
if( !cell )
{
cell = [[WorkoutCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: CellIdentifier];
}
}
I've a custom UITableViewCell subclass and I've read that this is supposed to be the correct way of loading custom cells for iOS 5:
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = [tv dequeueReusableCellWithIdentifier:#"customCell"];
if (cell == nil) {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"customCell"];
// Configure cell
cell.nameLabel.text = self.customClass.name;
}
return cell;
}
But the label text is not shown when I run the app. However, I also tried this way:
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tv dequeueReusableCellWithIdentifier:#"customCell"];
if (cell == nil) {
NSArray* views = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:nil options:nil];
for (UIView *view in views) {
if([view isKindOfClass:[UITableViewCell class]])
{
cell = (CustomCell *)view;
}
}
// Configure cell
((CustomCell *)cell).nameLabel.text = self.customClass.name;
}
return cell;
}
This way the label is displayed, but any reuseIdentifier is set in loadNibName: method. What the best way of loading custom cells should be? I need to support iOS 5+. Could the first approach not be working because I'd to configure cell's labels and styles in initWithStyle: method and not in the table view's method?
Thanks!
The error in your code is that cell.nameLabel.text is only set in the if (cell == nil) { ... } case and not generally.
The easiest ways to load custom cells are
Use registerNib:forCellReuseIdentifier: if the cell is defined in a nib file, or
use registerClass:forCellReuseIdentifier: if the cell is created programmatically, or
use a Storyboard and define "CustomCell" as "Prototype Cell" for the table view.
For example (in viewDidLoad):
[self.tableView registerNib:[UINib nibWithNibName:#"CustomCell" bundle:nil] forCellReuseIdentifier:#"customCell"];
Then dequeueReusableCellWithIdentifier
will always return a cell, so that cellForRowAtIndexPath simplifies to
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = [tv dequeueReusableCellWithIdentifier:#"customCell"];
cell.nameLabel.text = self.customClass.name;
return cell;
}
Just use this code and try.
static NSString *cellIdentifier=#"cell";
YourCustomCell *cell = (YourCustomCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
NSString *customeCellName = [NSString stringWithFormat:#"%#",[YourCustomCell class]];
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:customeCellName owner:self options:nil];
for (id currentObject in topLevelObjects)
{
if ([currentObject isKindOfClass:[UITableViewCell class]])
{
cell = (YourCustomCell *) currentObject;
break;
}
}
}
cell.nameLabel.text = self.customClass.name; // Make sure self.customclass.name have value.
return cell;
Use this code (NewCustomCell is your Custom UITableViewCell class name)...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
NewCustomCell *cell = (NewCustomCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nib=[[NSBundle mainBundle]loadNibNamed:#"NewCustomCell" owner:self options:nil];
cell=[nib objectAtIndex:0];
}
return cell;
}
Happy coding... :)
I am trying to put a cell as a space between each cell - which will be hidden by setting alpha = 0. In my table, the space cells will be for rows that are odd.
Note that the actual cell height is 85, but the hidden cell height (ie space between cells) is 20.
The problem is that the space cell height is 85, but not 20, I don't know why. Maybe the cell is not loaded correctly.
Cell here is the UITableViewCell - the actual cell - with identifier 'Cell'.
Cell2 is the space with identifier 'Space'.
Each class above has its own UITableViewCell class and the XIB files are also assigned to each of them. The identifier is also set in the IB for each Xib.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier1 = #"Cell";
static NSString *CellIdentifier2 = #"Space";
Cell *cell = (Cell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
if(!cell)
{
NSArray *ar = [[NSBundle mainBundle] loadNibNamed:#"CellView" owner:nil options:nil];
for (id obj in ar)
{
if ([obj isKindOfClass:[Cell class]])
{
cell = (Cell *)obj;
break;
}
}
}
if (indexPath.row % 2 == 1)
{
Cell2 *cell2 = (Cell2 *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if (!cell2)
{
NSArray *ar = [[NSBundle mainBundle] loadNibNamed:#"Cell2" owner:nil options:nil];
for(id obj in ar)
{
if([obj isKindOfClass:[Cell2 class]])
{
cell2 = (Cell2 *)obj;
break;
}
}
// Method 1
cell2 = [[Cell2 alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier2];
// Method 2
//cell2 = [[Cell2 alloc] init];
// Method 3
//cell2 = (Cell2 *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
[cell2.contentView setAlpha:0];
// prevent selection and other stuff
[cell2 setUserInteractionEnabled:NO];
}
return cell2;
}
else
{
// Configure the actual cell
}
return cell;
}
* I've renamed some of your NIB/Class names for a better understanding. *
First, you should register each cells' NIB:
- (void)viewDidLoad{
[super viewDidLoad];
static NSString *CellIdentifier1 = #"ContentCell";
static NSString *CellIdentifier2 = #"SpaceCell";
UINib *nib = [UINib nibWithNibName:#"CellViewNIBName" bundle:nil];
[self.tableView registerNib:nib forCellReuseIdentifier:CellIdentifier1];
nib = [UINib nibWithNibName:#"CellSpaceNIBName" bundle:nil];
[self.tableView registerNib:nib forCellReuseIdentifier:CellIdentifier2];
self.contentView.hidden = YES;
[self loadData];
}
Because you have the NIBs registered, dequeueReusableCellWithIdentifier: will always return a cell:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier1 = #"ContentCell";
static NSString *CellIdentifier2 = #"SpaceCell";
// Space Cell
if (indexPath.row % 2 == 1) {
CellSpace *cell = (CellSpace *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
return cell;
}
// Content cell
else {
CellView *cell = (CellView *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
// Configure cell
return cell;
}
}
Last, but not least, make sure to implement the following delegate method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Space cell's height
if (indexPath.row % 2 == 1) {
return 20.0f;
}
// Content cell's height
else {
return 80.0f;
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *returncell;
static NSString *cellIdentifier ;
if(indexPath.section == 0)
{
cellIdentifier = #"cell1";
}
else if (indexPath.section == 1)
{
cellIdentifier = #"cell2";
}
UITableViewCell *myCell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
MapTableViewCell *myCustomCell = (MapTableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(indexPath.section == 0)
{
if(myCell == nil)
{
myCell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
getLocationBtn = [UIButton buttonWithType:UIButtonTypeCustom];
getLocationBtn.frame = CGRectMake(myCell.frame.origin.x,myCell.frame.origin.y+5 , 200, 30);
[getLocationBtn setTitle:#"your button title" forState:UIControlStateNormal];
[getLocationBtn setTitleColor:[UIColor orangeColor] forState:UIControlStateNormal];
[getLocationBtn addTarget:self action:#selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
}
[myCell.contentView addSubview:getLocationBtn];
returncell = myCell;
}
else if (indexPath.section == 1)
{
if (myCustomCell == nil)
{
myCustomCell = [[MapTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
myCustomCell.nearbyLocation.text = #"demo Text";
returncell = myCustomCell;
}
return returncell;
}
//mycustom tablviewcell
import "MapTableViewCell.h"
#implementation MapTableViewCell
#synthesize nearbyLocation;
-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if(self)
{
self.backgroundColor = [UIColor groupTableViewBackgroundColor];
nearbyLocation = [[UILabel alloc]initWithFrame:CGRectMake(10, 5, 200, 30)];
[self addSubview:nearbyLocation];
}
return self;
}
#end
Best way to use number of custom cells with default cell
In addition for the answers provided, I want to emphasize on the Cell Identifier for each different custom cells must be different too.
For example custom cellA with identifier "Cell" and custom cellB with identifier "Cell2".