So I'm trying to store a cell's indexpath when my custom cell is created in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
I define a custom cell in class called "custom cell", and I added a property to that class defined as such:
#property (nonatomic, strong) NSIndexPath *indexPath;
in cellForRowAtIndexPath I set the index path with customCell.indexPath = indexPath.
When I NSLog it on the very next line it returns null. Could somebody please explain why this is happening?
Edit
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"EditableCell";
EditableCell *editableCell = (EditableCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (editableCell == nil) {
editableCell = [[EditableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
_myTextField = [editableCell textFieldCell];
if (indexPath.section == 0){
[_myTextField setPlaceholder:#"text"];
[_myTextField setReturnKeyType:UIReturnKeyNext];
}
else if (indexPath.section == 1){
[_myTextField setPlaceholder:#"text"];
[_myTextField setReturnKeyType:UIReturnKeyNext];
}
else {
[_myTextField setPlaceholder:#"text"];
[_myTextField setReturnKeyType:UIReturnKeyDone];
}
_myTextField.keyboardType = UIKeyboardTypeDefault;
_myTextField.delegate = self;
return editableCell;
}
Where I call [self.tableview indexpathforcell:cell]
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
if (textField.returnKeyType == UIReturnKeyNext) {
UITableViewCell* myCell = (UITableViewCell*)textField.superview;
EditableCell *currentCell = (EditableCell *)myCell;
NSLog(#"INDEXPATH OF CURRENT CELL: %#",[self.tableView indexPathForCell:currentCell]);
}
}
You can determine the indexPath of a given cell using
-[UITableView indexPathForCell:]
If the cell needs to know it's own indexPath:
NSIndexPath * myIndexPath = [(UITableView *)self.superview indexPathForCell:self]
But if it does, something's not right!
Looking at your edited post I see the problem. You need:
UITableViewCell* myCell = (UITableViewCell*)textField.superview.superview
The textField is actually a subview of the cell's contentView. This always seems a bit wrong to me, so another way to handle this is to make your custom cell the UITextFieldDelegate, and then create a delegate protocol for your cell. So within the cell you'd have:
(BOOL)textFieldShouldReturn:(UITextField *)textField {
if (textField.returnKeyType == UIReturnKeyNext) {
[self.delegate customCell: self textFieldDidReturn: textField];
}
return NO;
}
Then in your cell's delegate you'll have a reference to the cell and textField
Related
I have a table view that I want to show a checkmark accessoryType only in the cell that is selected, but now what I have is a checkmark for every cell that was selected...can someone please help me to fix this method?
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString * key = [self.settingsArray objectAtIndex:indexPath.row];
NSString * key2 = [self.soundsArray objectAtIndex:indexPath.row];
if (tableView.tag != 313) {
if([key isEqual:#"Reminder Sound"]){
[self reminderSoundPressed];
} else if([key isEqual:#"Sound"]){
}
}
UITableViewCell *newCell = [tableView cellForRowAtIndexPath:indexPath];
//setting the reminder
if (tableView.tag == 313) {
if ([key2 isEqual:#"Sound 1"]) {
[self.delegate setReminderSound:#"reminderSound1.wav"];
newCell.accessoryType = UITableViewCellAccessoryCheckmark;
}else if ([key2 isEqual:#"Sound 2"]) {
[self.delegate setReminderSound:#"reminderSound2.wav"];
newCell.accessoryType = UITableViewCellAccessoryCheckmark;
}else if ([key2 isEqual:#"Sound 3"]) {
[self.delegate setReminderSound:#"reminderSound3.wav"];
newCell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
}
thanks!!
When the user selects a row and you set the accessory type to checkmark, you have to loop through and change the accessory type for every other cell to none.
A easy solution is to implement the delegate function
- tableView:didDeselectRowAtIndexPath: and remove the checkbox there.
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryNone;
}
A more elegant solution is to make a custom UITableViewCell class and override the setSelected function.
- (void)setSelected:(BOOL)selected
animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
self.accessoryType = selected ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
}
Hey I'm working on a screen where user have option groups for example "Drink" which is title of section in my tableView, and their choices are "7up", "coke", etc which are cells of my table.
Now every Option Group choice (every cell in order words) has one radio button. I want to implement this. I'm facing problem if user selects any cell's radio button then other radio buttons should be deselected but how?
any help please
You should create a function to check your radio button from your custom cell and implements a delegate method to inform your TableViewController that your button on that cell was selected.
Your TableViewController needs to implements that delegate (dont forget to set each cell.delegate = self).
Then in your delegate method you create a loop to uncheck all of the radio buttons of the cells in the section except the cell you just checked.
Something like that :
This is a custom UITableViewCell with a button.
The images checked and uncheck need to look like a radio button checked and uncheked
Here is the .h file :
//RadioCell.h
#protocol RadioCellDelegate <NSObject>
-(void) myRadioCellDelegateDidCheckRadioButton:(RadioCell*)checkedCell;
#end
#interface RadioCell : UITableViewCell
-(void) unCheckRadio;
#property (nonatomic, weak) id <RadioCellDelegate> delegate;
#end
This is the .m file of RadioCell
//RadioCell.m
#property (nonatomic, assign) UIButton myRadio;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString*)reuseIdentifier
_myRadio = [UIButton buttonWithType:UIButtonTypeCustom];
[_myRadio setImage:[UIImage imageNamed:#"uncheck"] forState:UIControlStateNormal];
[_myRadio setImage:[UIImage imageNamed:#"check"] UIControlStateSelected];
[_myRadio addTarget:self action:#selector(radioTouched)orControlEvents:UIControlEventTouchUpInside];
_myRadio.isSelected = NO;
//don't forget to set _myRadio frame
[self addSubview:_myRadio];
}
-(void) checkRadio {
_myradio.isSelected = YES;
}
-(void) unCheckRadio {
_myradio.isSelected = NO;
}
-(void) radioTouched {
if(_myradio.isSelected == YES) {
return;
}
else {
[self checkRadio]
[_delegate myRadioCellDelegateDidCheckRadioButton:self];
}
}
Now just adapt your tableview controller with RadioCell (in .m file)
//MyTableViewController.m
#interface MyTableViewController () <RadioCellDelegate>
#end
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"RadioCell";
RadioCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[RadioCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel = #"Coke"; //or whatever you want
cell.delegate = self;
return cell;
}
-(void) myRadioCellDelegateDidCheckRadioButton:(RadioCell*)checkedCell {
NSIndexPath *checkPath = [self.tableView indexPathForCell:checkedCell];
for (int section = 0; section < [self.tableView numberOfSections]; section++) {
if(section == checkPath.section) {
for (int row = 0; row < [self.tableView numberOfRowsInSection:section]; row++) {
NSIndexPath* cellPath = [NSIndexPath indexPathForRow:row inSection:section];
RadioCell* cell = (CustomCell*)[tableView cellForRowAtIndexPath:cellPath];
if(checkPath.row != cellPath.row) {
[cell unCheckRadio];
}
}
}
}
}
Simple solution for a 2-option radio button UITableView (but you get the idea):
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSIndexPath *newIP;
if (!indexPath.row)
newIP = [NSIndexPath indexPathForRow:indexPath.row+1 inSection:0];
else
newIP = [NSIndexPath indexPathForRow:indexPath.row-1 inSection:0];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark)
cell.accessoryType = UITableViewCellAccessoryNone;
else{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
UITableViewCell *newCell = [tableView cellForRowAtIndexPath:newIP];
newCell.accessoryType = UITableViewCellAccessoryNone;
}
}
One solution would be to make use of the table views native selection capabilities.
In a standard UITableView it's only possible to have one row selected at a time and you can use this to your advantage. By setting "Selection" in storyboard to "None" the selection of a row will not be visible.
Now you can implement your own selection display. You can override the method -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath to update your cell when it gets selected.
And you can override the method -(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath to change the cell when it's no longer selected.
UITableViewDelegate automatically calls didSelectRowAtIndexPath on the old selection, when a new selection is made, keeping the selection unique like radio buttons.
I put together a little sample project for you to try, you can download it here.
Hopefully, I have been at least a bit helpful.
Cheers!
I am using tableview apple's lazy loading code in my project,but having exception in project. And error is - *** Assertion failure in -[UITableView _configureCellForDisplay:forIndexPath:],here is my code please help.But it is working in other project.I have no delegate method.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"LazyTableCell";
static NSString *PlaceholderCellIdentifier = #"PlaceholderCell";
NSUInteger nodeCount = [self.entries count];
if (nodeCount == 0 && indexPath.row == 0)
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:PlaceholderCellIdentifier];
cell.detailTextLabel.text = #"Loading…";
return cell;
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (nodeCount > 0)
{
AppRecord *appRecord = [self.entries objectAtIndex:indexPath.row];
cell.textLabel.text = appRecord.name;
if (!appRecord.appIcon)
{
if (self.mytable_view.dragging == NO && self.mytable_view.decelerating == NO)
{
[self startIconDownload:appRecord forIndexPath:indexPath];
}
cell.imageView.image = [UIImage imageNamed:#"Placeholder.png"];
}
else
{
cell.imageView.image = appRecord.appIcon;
}
}
return cell;
}
Because cellForRowAtIndexPath is returning a nil value and then configureCellForDisplay is expecting a UITableViewCell. The storyboard or XIB does not have a cell defined with the cell identifier you specified. Better check the spelling of identifier.
Please check for Delegate.
Have you added both delegate or not?
UITableViewDelegate, UITableViewDataSource
import UIKit
class UserFriendVC: UIViewController, UITableViewDelegate, UITableViewDataSource
{
override func viewDidLoad() {
super.viewDidLoad()
}
}
you should add cellIdentifier from "Show the attributes inspector". Please fallow just like below snippet.
Firstly added below code to your-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath delagate method.
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
ResultCustomTableViewCell *cell = (ResultCustomTableViewCell *)[resultTableView dequeueReusableCellWithIdentifier:#"ResultTableViewCellIdentifier"];
...
//set the cell property
...
return cell;
}
and then jump the "Show the attributes inspector", While selected cell root view.
And then paste the same identifier name to identifier section in "Show the attributes inspector". in this case i use this ResultTableViewCellIdentifier.
And one more think. if you use custom cell just like this scenario, you must add below delegate metod. Because your custom cell height can be higher or smaller original tableview height. And Also you should register this nib in viewDidLoad.
- (void)viewDidLoad {
[resultTableView registerNib:[UINib nibWithNibName:#"ResultCustomTableViewCell" bundle:nil] forCellReuseIdentifier:[ResultCustomTableViewCell reuseIdentifier]];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
CGFloat height = 0.0;
if (tableView == resultTableView){
height = 44.0f;
}
return height;
}
i hope, it'll fix your problem
CellIdentifier I bet your cellForRowAtIndexPath is returning nil.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"LazyTableCell";
static NSString *PlaceholderCellIdentifier = #"PlaceholderCell";
NSUInteger nodeCount = [self.entries count];
if (nodeCount == 0 && indexPath.row == 0) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:PlaceholderCellIdentifier];
if(cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:PlaceholderCellIdentifier] autorelease];
}
cell.detailTextLabel.text = #"Loading…";
return cell;
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
if (nodeCount > 0) {
AppRecord *appRecord = [self.entries objectAtIndex:indexPath.row];
cell.textLabel.text = appRecord.name;
if (!appRecord.appIcon)
{
if (self.mytable_view.dragging == NO && self.mytable_view.decelerating == NO)
{
[self startIconDownload:appRecord forIndexPath:indexPath];
}
cell.imageView.image = [UIImage imageNamed:#"Placeholder.png"];
}
else
{
cell.imageView.image = appRecord.appIcon;
}
}
return cell;
}
That's probably why [UITableView _configureCellForDisplay:forIndexPath:] is failing... because cellForRowAtIndexPath is returning a null value and then configureCellForDisplay is expecting a UITableViewCell.
Register your cell in the - (void)viewDidLoad method using
[self.tableView registerClass:UITableViewCell.class forCellReuseIdentifier:#"Your Reuse Identifier"];
if your are using storyboards and use this if you are using a custom cell.
[self.tableView registerNib:UINib nibWithNibName:#"Your File Name.xib" bundle:nil forCellReuseIdentifier:#"Your Reuse Identifier"]
I want to set the text of a custom cell that inherits from UITableViewCell with my own method, here's my code:
- (void)updateCell {
NSIndexPath* indexPath;
indexPath= [NSIndexPath indexPathForRow:0 inSection:1];
Somecell *cell = (Somecell *)[mytblview cellForRowAtIndexPath:indexPath];
cell.b_freq.text = #"12332123";
[mytblview reloadData];
}
This code is not updating my UITableView as well. Are there any mistakes in my code or do you suggest using a different method?
You need to implement the UITableViewDataSource delegate method yourself rather than calling it and then modifying the cell that is returned:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
if (indexPath.section == 1 && indexPath.row == 0) {
Somecell *cell = [[Somecell alloc] init];
cell.b_freq.text = #"12332123";
return cell;
}
}
Implement the method and then return the cell that you want.
Check out the Apple documentation for more info.
I have a UITableView with one section. All of the cells in that one section have cells that are derived from a subclass of UITableViewCell called PLContactCell.
What I'd like to do is, for the very last row of the table only, not use a PLContactCell. I just want to use a normal UITableViewCell that I can format however I would like. I'd also like to be able to have this cell NOT respond to being tapped.
My initial cellForRowAtIndexPath method is:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
PLContactCell *cell = [tableView dequeueReusableCellWithIdentifier:[PLContactCell reuseIdentifier]];
if (!cell) {
cell = [PLContactCell reusableCell];
cell.delegate = self;
}
id modelObject = [[sections objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
if ([modelObject isKindOfClass:[NSString class]]) {
[cell configureWithString:modelObject];
} else {
[cell configureWithUser:modelObject];
}
return cell;
}
EDIT
So I tried created a UITableView cell in the XIB file and added the reuse identifier of "newCell" to it. Then I added this code:
if (indexPath.row == [[sections objectAtIndex:indexPath.section] count] - 1) {
NSString *CellIdentifier = #"newCell";
noFormatCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
}
This doesn't do anything. My question is, how do I access the last row of the section and how do I make it so that that cell it is not a PLContactCell but a UITableView Cell.
If it's always at the end, you might consider using the footer view of the UITableView. You can then keep some extra logic out of your UITableViewDataSource.
If it HAS to be as a cell, you'd have to add an extra row count on your last section, then do an if statement check to watch out for it in your -tableView:cellForRowAtIndexPath: implementation. I would strongly urge you try the footer approach, as it's cleaner and way easier to figure out what you were doing a few months/years from now.
Here's some code. Note you'd need to make another section if you are using grouped style in the UITableView.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == sections.count - 1) //Looking for last section
{
return [sections objectAtIndex:section].count + 1; //Add one to the last section
}
return [sections objectAtIndex:section].count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger row = indexPath.row;
if ((sections.count == indexPath.section) && [sections objectAtIndex:indexPath.section].count == indexPath.row)
{
//Here you would create and return your UITableViewCell
}
PLContactCell *cell = [tableView dequeueReusableCellWithIdentifier:[PLContactCell reuseIdentifier]];
if (!cell) {
cell = [PLContactCell reusableCell];
cell.delegate = self;
}
id modelObject = [[sections objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
if ([modelObject isKindOfClass:[NSString class]]) {
[cell configureWithString:modelObject];
} else {
[cell configureWithUser:modelObject];
}
return cell;
}