14

I have two textfields in a custom cell how to get the indexpath value of Tableview cell in textfield delegate methods I want to get the input value from user and save it to the relavent object. the user can add more cells by clicking button(Add More) in cell..

enter image description here

Thanks in Advance...

skywinder
  • 21,291
  • 15
  • 93
  • 123
Deepak
  • 439
  • 1
  • 5
  • 13
  • possible duplicate of [Pass an argument to selector](http://stackoverflow.com/questions/12297511/pass-an-argument-to-selector) –  Sep 07 '12 at 13:30
  • for swift 4, you can refer my git repo https://github.com/dpakthakur/tableviewCellReuse – Deepak Thakur Sep 02 '18 at 17:37

11 Answers11

19

Update to iOS7!

With new features in iOS7 now code should be :

UITableViewCell *textFieldRowCell;

if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
    // Load resources for iOS 6.1 or earlier
    textFieldRowCell = (UITableViewCell *) textField.superview.superview;

} else {
    // Load resources for iOS 7 or later
    textFieldRowCell = (UITableViewCell *) textField.superview.superview.superview; 
   // TextField -> UITableVieCellContentView -> (in iOS 7!)ScrollView -> Whoola!
}

NSIndexPath *indexPath = [self.tableView indexPathForCell:textFieldRowCell];
Shmidt
  • 16,436
  • 18
  • 88
  • 136
skywinder
  • 21,291
  • 15
  • 93
  • 123
13

A more dynamic solution (no hardcoded superview levels and same code for different iOS versions).

Further, indexPathForCell: will not work if the cell is not visible, therefore I use indexPathForRowAtPoint: as workaround.

//find the UITableViewcell superview
UIView *cell = textField;
while (cell && ![cell isKindOfClass:[UITableViewCell class]])
    cell = cell.superview;

//use the UITableViewcell superview to get the NSIndexPath
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:cell.center];
Daniel
  • 20,420
  • 10
  • 92
  • 149
10

This is how I have been doing it and have been having better luck. I grab the origin of the textField frame. Convert that to a point. Then convert the point to an index path.

-(void)textFieldDidBeginEditing:(UITextField *)textField
{
    CGPoint origin = textField.frame.origin;
    CGPoint point = [textField.superview convertPoint:origin toView:self.tableView];

    NSIndexPath * indexPath = [self.tableView indexPathForRowAtPoint:point];

    [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];

}
Kerkness
  • 329
  • 4
  • 9
4

Try this method to get textfield dynamically anywhere from your tableview controller

 #pragma mark - Get textfield indexpath
- (NSIndexPath *)TextFieldIndexpath:(UITextField *)textField
{
    CGPoint point = [textField.superview convertPoint:textField.frame.origin toView:self.TblView];
    NSIndexPath * indexPath = [self.TblView indexPathForRowAtPoint:point];
    NSLog(@"Indexpath = %@", indexPath);
    return indexPath;
}
Rajesh Loganathan
  • 11,129
  • 4
  • 78
  • 90
2

To get The indexPath try the following code.

    UIView *contentView = (UIVIew *)[textfield superview];
    UITableViewCell *cell = (UITableViewCell *)[contentView superview];
    if(IS_IOS7_OR_GREATER) {
        cell = (UITableViewCell *)[[contentView superview] superview];
    }
    NSIndexPath *indexPath = [self.tableview indexPathForCell:cell];

Tats it you are done.

To be simple,

NSIndexPath *indexPath = [self.tableview indexPathForCell:(UITableViewCell *)[(UIVIew *)[textfield superview] superview]];

if(IS_IOS7_OR_GREATER) {
    cell = (UITableViewCell *)[[[textfield superview] superview] superview];
}

Check the updated answer.

Sasi
  • 1,666
  • 2
  • 24
  • 44
2

In case somebody like me needs @Kerkness' answer (this one really worked for me) in swift:

func textFieldDidBeginEditing(_ textField: UITextField) {
    let origin: CGPoint = textField.frame.origin
    let point: CGPoint? = textField.superview?.convert(origin, to: tableView)
    let indexPath: IndexPath? = tableView.indexPathForRow(at: point ?? CGPoint.zero)
    tableView.scrollToRow(at: indexPath!, at: .middle, animated: true)
}    

It should be straight forward enough: you get the point then you get the indexPath and do whatever you need with it!

tospig
  • 7,762
  • 14
  • 40
  • 79
Rob
  • 2,243
  • 4
  • 29
  • 40
1

set cell indexpath value to UITextField tag property and you can access the indexpath in delegate methods like textfield.tag

prashant
  • 1,920
  • 14
  • 26
  • but i have two text fields if its one i can use as u said – Deepak Sep 07 '12 at 13:33
  • Both textfield will be having the unique indexpath in tag. Then you can check for placeholder to determine which is url and which is name textfield.like this NSLog(@"%@",self.textField.placeholder); if([self.textField.placeholder isEqualToString:@"Enter name"]) – prashant Sep 07 '12 at 13:49
  • i think that you wanted let me know if you still hang with that – prashant Sep 07 '12 at 13:51
1

You can set the tags of textfields in cellForRowAtIndexPath: such that it stores info of both cell and text field

For example : If it is cell in 4th row, tag of 1st and 2nd textfields can be 41 and 42 respectively. Similarly, tags of textfields should be 51 and 52 for 5th row and so on...

Then in textfield delegate method, you can get textfield.tag to identify active textfield.

Shahrukh Malik
  • 242
  • 2
  • 15
1

This can be done in the Objective-C runtime for any instance (doesn't have to be UITextField), with any associated object (doesn't have to be NSIndexPath).

For this question, we could create a category UIView+RepresentingIndexPath.

Our interface allows us to set and retrieve an NSIndexPath:

@interface UIView (RepresentingIndexPath)
- (void)representIndexPath:(NSIndexPath *)indexPath;
- (NSIndexPath *)representedIndexPath;
@end

Our implementation uses Objective-C associated objects to set and retrieve an index path on a view:

#import "UIView+RepresentingIndexPath.h"
#import <objc/runtime.h>

static char IndexPathKey;

@implementation UIView (RepresentingIndexPath)

- (void)representIndexPath:(NSIndexPath *)indexPath
{
    objc_setAssociatedObject(self, &IndexPathKey, indexPath, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSIndexPath *)representedIndexPath
{
    return objc_getAssociatedObject(self, &IndexPathKey);
}

@end

In action:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    TextFieldTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TextFieldCell" forIndexPath:indexPath];
    [cell.textField addTarget:self action:@selector(textFieldTextChanged:) forControlEvents:UIControlEventEditingChanged];
    [cell.textField representIndexPath:indexPath];
    return cell;
}

- (void)textFieldTextChanged:(UITextField *)sender
{
    NSIndexPath *indexPath = [sender representedIndexPath];
    NSLog(@"%@", indexPath);
}

One final note! Messing around in the runtime should really be avoided if you can achieve what you're trying to do without doing so. Just thought I'd add another solution!

Adam Waite
  • 19,175
  • 22
  • 126
  • 148
1

I find this answer searching how can I find the index path of a cell with inside a UITextField.

So, thanks to the answer above, I put my code here, hoping might be usefull.

- (void)searchSelectedIndexPath:(UIView*)view {
    // This allow to find selected index path for a table view cell with a text field inside.
    for (UIView* subview in view.subviews) {
        if ([view isKindOfClass:[UITextField class]]) {
            if ([view isFirstResponder]) {
                UIView *cell = view;
                while (cell && ![cell isKindOfClass:[UITableViewCell class]]) {
                    cell = cell.superview;
                }
                self.selectedIndexPath = [self.tableView indexPathForRowAtPoint:cell.center];
                return;
            }
        }
        [self searchSelectedIndexPath:subview];
    }
}

In this way, when keyboard notification will be raise:

- (void)keyboardDidShow:(NSNotification*)notification {
    [self searchSelectedIndexPath:self.tableView];
}
Luca Davanzo
  • 21,000
  • 15
  • 120
  • 146
-1

Thanks, @Luka, it works in a great way. Here is the swift 4 solution,

var selectedIndexPath: IndexPath?

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShowHide(_ :)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShowHide(_ :)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)

}


func searchSelectedIndexPath(view: UIView) {
    view.subviews.forEach { (subview) in
        if view is UITextView, view.isFirstResponder == true {
            var cell:UIView? = view;
            while cell != nil && !(cell is UITableViewCell) {
                cell = cell?.superview;
            }
            if cell != nil {
                self.selectedIndexPath = self.dashBoardTableView.indexPathForRow(at: (cell?.center)!)
                return
            }
        }
        self.searchSelectedIndexPath(view: subview)
    }
}

// Keyboard notification observer menthod
@objc fileprivate func keyboardWillShowHide(_ notification: NSNotification){
     if notification.name == NSNotification.Name.UIKeyboardWillShow {

        UIView.animate(withDuration: duration, animations: { () -> Void in
            self.selectedIndexPath = nil;
            self.searchSelectedIndexPath(view: self.tableView)
            if let indexpath = self.selectedIndexPath {
                self.tableView.scrollToRow(at: indexpath, at: .top, animated: false)
            } else{
                self.bottomContriant.constant = keyboardHeight
                self.view.layoutSubviews()
            }
        })
    } else {
        self.bottomContriant.constant = 15
        UIView.animate(withDuration: duration, animations: { () -> Void in
            self.view.layoutIfNeeded()
        })
    }
}