get UITableViewCell from NSIndexPath? - ios

I am using multiple UITableView with custom cells in a single viewController. Custom cell have textFields, I am able to edit the textFields. Now I want to get the tableViewCell of exact UITableView in the textField delegate method when am editing the textField ?
Remember there are multiple tableViews I want to get the exact cell of exact table which am editing. Any Help?

You must have tag to your both tableview
use below code in textfield delegate
UITableViewCell *cell = (UITableViewCell *) textField.superview.superview.superview;
UITableView *curTableView = (UITableView *)cell.superview;
NSIndexPath *indexPath = [curTableView indexPathForCell:cell];

NEVER loop through superviews, the correct and most reliable way to do what you want is:
CGPoint textViewPosition = [textView convertPoint:CGPointZero toView:self.tableView];
CGRect senderFrame = CGRectMake(textViewPosition, textViewPosition, textView.frame.size.width, textView.frame.size.height);
NSArray *indexPaths = [self.tableView indexPathsForRowsInRect:senderFrame];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:[indexPaths firstObject];
This may get more complex as you have different table views in 1 view, I suggest rethinking why you have more than 1 table view and see if you can't do this in a more efficient way i.e. 1 table view with custom sections etc...

Related

How do I determine the indexPath for cell with a switch that has been tapped?

I have a UITableView with prototype cells that have a UISwitch on them. When the user taps the switch on any particular cell, I need to determine which object in my datasource has had its switch toggled.
Here is my method for the switch:
- (IBAction)completeSwitchTapped:(id)sender {
UITableViewCell *cell = (UITableViewCell *)[sender superview];
NSIndexPath *indexPath = [self.itineraryTableView indexPathForCell:cell];
NSLog(#"cell row is: %d in section: %d", indexPath.row, indexPath.section);
}
But this always returns row 0 in section 0 regardless of which row or section was picked.
How do I properly return the correct cell which contains the switch? Clearly [sender superview] isn't working and I'm considerably at a loss for how to reference the cell.
Thanks!
Try something like this:
UIView *superview = sender.superview;
while (![superview isKindOfClass:[UITableViewCell class]] && superview.superview != nil) {
superview = superview.superview;
}
NSIndexPath *indexPath = [self.itineraryTableView indexPathForCell:superview];
When creating the button/switch, set it's tag to the cell row or some other meaningful value. Then simply extract sender.tag when the IBAction method is invoked, to retrieve the cell row.
When I have to do buttons and switches like this in my own tables, I usually subclass UIButton or UISwitch and in my subclass, I add a ".indexPath" or ".row" property to my subclassed control.
Which I set when I return the freshly populated (or reset) table view cell in "cellForRowInIndexPath:"
That way, when your switch or button is touched, you'll have a property that has the correctly set row index ready for you to work with.
A much more straightforward & less janky solution versus doing "superview.superview".

Detect the last UITableViewCell of the current visible in UITableView

I would like to know if there is a way to detect if the current UITableViewCell is the last one in view then when the user pressed enter you will scroll the UITableView using this code
int cellHeight = 44;
[finishingTableView setContentOffset:CGPointMake(finishingTableView.contentOffset.x,finishingTableView.contentOffset.y + cellHeight) animated:YES];
I have a UITableView with custom UITableViewCells, each UItableViewCell has a UITextfield and I am programmatically selecting the UITableViewCell then making the cells textfield become first responder. I want to allow the user to hit enter all the way to the bottom of the UITableView but only start scrolling when the next UITableViewCell to select is out of view.
Use the indexPathsForVisibleRows method of UITableView.
NSArray *visibleRows = [self.tableView indexPathsForVisibleRows];
NSIndexPath *lastRow = [visibleRows lastObject];
Then compare that to the indexPath you have for the cell you are dealing with.

Update label on UITableViewCell

I have a NSTimer that calls this method every fourth second:
- (void)timerDecrement
{
timerCount = timerCount-1;
[OtherViewControllerAccess updateTimeLeftLabel];
}
In the updateTimeLeftLabel in the other class:
- (void)updateTimeLeftLabel
{
int timeLeft = OtherClassAccess.timerCount;
UILabel *timeLeftLabel = [[UILabel alloc] initWithFrame:CGRectMake(200, 10, 120, 20)];
timeLeftLabel.text = [NSString stringWithFormat:#"Tid kvar: %ih", timeLeft];
[cell addSubview:timeLeftLabel];
}
Basically I want my app to update a label in a cell in the tableview with the current time left, but the above method doesn't do anything to the call. So my question is, how can I add this subview to the cell outside the cellForRowAtIndexPath:delegate method, and then make it update that label every time the method is called.
So my question is, how can I add this subview to the cell outside the
cellForRowAtIndexPath:delegate method, and then make it update that
label every time the method is called.
The answer is, don't add subviews to a table view cell outside of cellForRowAtIndexPath. The cells belong to the table view, and you absolutely, categorically, should NOT try to modify them. That's the table view's job.
Just as a small example of what's wrong with your code, you would be adding an ever-increasing number of label views to your table view cell, one every 1/4 second. That's bad.
Second point: Which cell is "cell"? A table view manages a whole table of cells. If the user scrolls, some cells are scrolled off-screen and replaced with different cells.
Instead, you should figure out which indexPath contains the cell with your data in it, change the data in your model, and tell your table view to update the cell at the appropriate indexPath. That will cause it to redraw with updated contents.
Here is how I did something similar. I created a custom UITableViewCell class that has a timestamp UILabel:
#property (nonatomic) UILabel *labelTimestamp;
In that cell's layoutSubviews, I update the label size based on its title.
- (void)layoutSubviews {
[super layoutSubviews];
[self.labelTimestamp sizeToFit];
...
}
I then have an NSTimer firing every minute in my UIViewController that update that label in every visible cell (you could adapt to update only one cell with a specific indexPath).
- (void)timerDidFire
{
NSArray *visibleCells = [self.tableView visibleCells];
for (GroupViewCell *cell in visibleCells) {
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
[cell.labelTimestamp setText:[self.groupController statusUpdateDateAtIndexPath:indexPath]];
[cell setNeedsLayout];
}
}
I would keep the set up of the cell's centralized in cellForRowAtIndexPath: method. You can keep using your NSTimer to call reloadRowsAtIndexPaths:withRowAnimation: with the indexes of the cell/cells you want to update and therefore cellForRowAtIndexPath: will be called again.
Why don't you put that value (which you want to display in the cell) in a variable and assign a UILabel that value. In your updateTimeLeftLabel just call [self.tableView reloadData].
You can reload whole table or some specific rows but that needs connection of datasource with your views . You have to change your dataset first and then you have to call
[self.tableview reloadData];
another method is that, after changing dataset call
[self.tableview reloadRowsAtIndexPaths:indexPath withAnimation:animation];
2nd method requires indexPath i.e. you know that which cell you need to edit .
My problem was same . In my project there were 2 TextFields and 1 label in each cell . Now depending on the values of 2 textfields, I have to show their multiplication in UILabel. and this is my code.
-(void)textFieldDidChange:(id)sender{
UITextField *_sender = (UITextField *)sender;
int tag = _sender.tag;
int row = tag / 3;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
((UILabel *)[[self.tableView cellForRowAtIndexPath:indexPath] viewWithTag:row * 3 + 2]).text = #"hello";
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"here");
static NSString *CellIdentifier = #"procedureDetailsCell";
UITableViewCell *cell = (procedureCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if ( cell == nil ) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
[((procedureCell *)cell).Quantity setTag:indexPath.row + 0];
[((procedureCell *)cell).Quantity addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
[((procedureCell *)cell).Cost setTag:indexPath.row + 1];
[((procedureCell *)cell).Cost addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
[((procedureCell *)cell).total setTag:indexPath.row + 2];
return cell;
}
Logic is simple I have used Custom TableViewCell which contains 2 textfields and 1 label. when one of the two textfield's value is changed we are calling "textFieldDidChange" method which finds indexpath and then find UITableViewcell and then updates its lastview's text value, that is our UILabel. we have to give unique tag to each of our views .

How to get UITableViewCell's index from its UITextField?

I have a UITextField in a custom cell inside table. I created new class DataCell which is subclass of UITableViewCell. Inside DataCell I created outlets for textfields and I also have method inside implementation file which uses 'editing did end' and I manipulate textField values there.
I am now wondering how to get rowIndex or number of the cell, as each time I click + button new custom cell is loaded on the table. If I get tag I always get same tag number regardless of the cell I selected.
The text field passed to your delegate is a subview of the cell's contentView.
UITableViewCell *cell = (UITableViewCell*) textField.superview.superview;
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
You can use this logic when you are not sure of hierarchy between textfield and cell.
UITableViewCell *cell = nil;
UIView *parentView = textField.superview;
while(parentView) {
if([parentView isKindOfClass:[UITableViewCell class]]) {
cell = parentView;
break;
}
parentView = parentView.superview;
}
if(cell)
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
Add tags to the text field in the tableView:cellForRowAtIndexPath: method. In this example, I have a custom cell with a label and a text field:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
RDCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.label1.text = self.theData[indexPath.row];
cell.textField.tag = indexPath.row;
return cell;
}
It sounds like you are maybe handling the end of editing in your custom cell class, but you might want to consider doing it in the table view controller instead, since that gives you easy access to the model, which I presume you are modifying with what the user types in the text field. If you do that, then you should connect the text field's delegate property up to the table view controller in IB.
If we're accepting fragile answers then for the sake of contributing something new to the conversation:
CGRect rectInTableView =
[tableView convertRect:textField.bounds fromView:textField];
NSUInteger indexOfCellContainingTextField =
(NSUInteger)(rectInTableView.y / tableView.rowHeight);
Assumptions that make it fragile: (i) all rows are the same height; (ii) the height is set on the table view. If you haven't implemented UITableViewDelegate -tableView:heightForRowAtIndexPath: then both of those assumptions will hold true. You're also taking advantage of the fact that casting a positive float to an integer rounds down.
I would argue that although still not completely clear of assumptions, this is less fragile than Mundi's solution because it makes assumptions only about things you do directly control (ie, cell sizing) and not about things you don't (ie, the view hierarchy UIKit uses internally to present table views).

Getting index path of the table

I am using group of buttons with different images and tableview with custom cell in my project.every cell having group of components (like imageview,button,label,slider) when pressing each button one cell will be added.
My button image and also added to imageview of the cell.
How can i get the index of each cell when pressing the button again.
cell will be added when i press the button at first time.
when pressing second time i want to increment the label value inside the cell.so i need the indexpath to cell the cell from the tableview.
I'm not sure exactly what you're looking for, maybe you can clarify what you're trying to do.
The method indexPathForCell: is a UITableView method that gives you the index of a certain cell.
Clarify your question a bit and maybe we can help more.
You can call button touch event to get the cell of uitableview -
UIView *cellView = (UIVIew *)[button superview];
UITableViewCell *cell = (UITableViewCell *)[cellView superview];
NSIndexPath *indexPath = [self.tableview indexPathForCell:cell];
Without knowing the structure of your cells, table, or anything like that. this code will work.
-(NSIndexPath *) pathForButton:(UIbutton *) b {
UITableView *tv = nil;
UIView *superView = [b superview];
UIView *cell;
while(superview != nil && ![superview isKindOfClass:[UITableView class]]){
cell = superview;
superview = [superview superview];
}
if(superview != nil && cell != nil){
tv = (UITableView*)superview;
return [tv indexPathForCell:cell];
}
return nil;
}

Resources