I've created a table where each cell holds both a text label and a text field. I'm adding the textfields as such [cell addSubview:passwordField]; and from a visual perspective they appear and are editable, etc....
The problem arises when I attempt to retrieve the entered values from the textfields. I iterate over the cells and try to grab the subview (IE the textfield), however, my iteration only discovers the text label.
Here is the code I'm using to search:
for(NSInteger i =0; i < [tableView numberOfRowsInSection:0]; i++){
NSIndexPath *path = [NSIndexPath indexPathForRow:i inSection:0];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:path];
UIView* subView = [[cell.contentView subviews]lastObject]; // I've also tried object at index here
// Anything beyond this is just matching....
Another approach I took was recursively searching the subviews, but, again that yielded no results.
You have added your textField on subView of cell.
[cell addSubview:passwordField];
While you're trying to find it on cell.contentView.
Add your textField as a subView of cell.Contentview
[cell.contentView addSubview:passwordField];
And find it in this way -
for(UIView *view in [cell.contentView subviews])
{
if([view isKindOfClass:[UITextfield class]])
{
UITextField *textField = (UITextField *)view;
NSLog(#"%#",textField.text);
}
}
Why not have a datasource mapped to the TableView and just retrieve / update the values in the datasource. You can then call reloadRowsAtIndexPaths to load just the row you just changed. Trying to iterate through the TableView rather than just updating the datasource seems very inefficient.
Instead of UIView* subView = [[cell.contentView subviews]lastObject]; you can try to find it as:
for(UIView *view in [cell subviews])
{
if([view isKindOfClass:[UITextfield class]]){
// view is the reference to your textfield
}
}
That way you can add other UIViews as subviews and still get the reference of the textfield without having to keep track of its subview index.
2 things occur to me:
In the long run it'll be easier to create a UITableViewCell which contains a UITextField which is accessible as a property. You can either use a nib to layout the cell or do it programmatically in the cells init method. This approach will make your code easier to manage.
You need to consider cell reuse. If you are reusing cells (which you should be) then you will need store the fetch the value from the textfield before it is reused.
Related
In my custom cell there is a UILabel and one UIButton. Whenever I click on that UIButton the UILabel's height is increased as per content of the label.
The problem is that how can I get that UILabel that is a subview of a cell. Every cell contains a label and a button but only that UILabel is increased that the cell button is clicked, others remain as they are.
Thanks in advance.
You can go through all subviews in the cell and see which one is a UILabel:
for(UIView *v in [cell subviews])
{
if([v isKindOfClass:[UILabel class]])
//you can put more checks to see if height is to be increased/decreased
[v setFrame:CGRectMake(origin.x,origin.y,width,height)];
}
For this you have need to assign TAG for every component..
Try bind the method to your button may work for you.
-(void)buttonClick:(id)sender {
UITableViewCell *cell=(UITableViewCell*)[sender superview];
NSArray *subviews=[cell subviews];
for (int i=0; i<[subviews count]; i++) {
id object=[subviews objectAtIndex:i];
if([object isKindOfClass:[UILabel class]]){
//do stuff here
}
}
}
The easiest way is to assign the tag property to the labels. That way in your button action method you can find the relevant label. For example:
- (void) myButtonAction: (UIButton *) sender
{
UILabel *theLabel = (UILabel *) [sender.superview viewWithTag: MYLABELTAG];
// Do something with theLabel
}
What this code does is finds the label in the same view as the button is in.
I wrote a short example on how to get labels from tablecells here: https://stackoverflow.com/a/9864169/407488
But i think what you want is to increase all labels in all cells at once? Then just use reloadData and change a member variable before calling it (when touching the button). You read that member in your cellForRow: code and assign the height appropriate.
I have created the cells with labels and using checkaMarksAccessory. The few last cells have UITextFields which can user modifi, and those have selector on UIControlEventEditingDidEnd where i want change the state of the cell to checked.
How can i get the cell in the selector? Doesn't have the object some parentView?
The way i inserting the object to cell.
UITextField *textfield = [[UITextField alloc] initWithFrame:CGRectMake(10, 25, 200, 30)];
[textfield setBorderStyle:UITextBorderStyleRoundedRect];
[textfield addTarget:self action:#selector(vybavaDidFinishEdit:) forControlEvents:UIControlEventEditingDidEnd];
[cell.contentView addSubview:textfield];
I'm not sure if it's safe to assume cell.contentView.superview == cell. Might Apple change this? I doubt it. But, I don't see anywhere in the documentation that says a cell's content view is a direct subview of the cell.
If you've added a UIGestureRecognizer to one of your subviews of the cell's content view, then you can get a reference to the cell with:
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:[gestureRecognizer locationInView:self.tableView]];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
Table View Animations and Gestures sample code uses indexPathForRowAtPoint: this way.
If you must traverse superviews, I think using a function like the one below is a bit safer.
UITableViewCell *ACMContentViewGetCell(UIView *view)
{
while ((view = view.superview)) {
if ([view isKindOfClass:[UITableViewCell class]]) {
return (UITableViewCell *)view;
}
}
return nil;
}
But that function still assumes contentView is within its cell, which I also didn't see anywhere in the documentation.
So perhaps, the best solution is to rearchitect your code so that you don't need to get cell from contentView, or if you must, then add an instance variable from the subview of contentView to cell.
ok so the way is to use superview. The superview is component which own the object. If i want get the UITableViewCell from UITextField i used [[UITextField superview] superview].
How can I eliminate views created upon selecting a cell in UITableView when the cell is no longer selected or other cell is on selection.
Suppose I have the code below for didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
CGSize cellSize = [tableView cellForRowAtIndexPath:indexPath].frame.size;
UIView *selectionView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, (int)cellSize.width, (int)(cellSize.height + 100))];
selectionView.layer.borderWidth = 2;
[[tableView cellForRowAtIndexPath:indexPath]addSubview:selectionView];
}
Now, I want to remove that created selectionView when I focus on another cell and create it again to the cell which I am focusing.. The problem is that when I select a cell for the first time, it works perfectly but when I select another cell, the selectionView created from the previous cell still does not disappear and it duplicates the view already. How am I suppose to solve this? Need suggestion.. :( thanks..
You need to add tag for the selectionView as follows
selectionView.tag = 100;
Also , you need to have the reference of the last selected indexPath by declaring a NSIndexPath class member and retaining it.
So while selecting a new cell, get the cell with last selected indexpath and remove the view from the cell as follows
UITableViewCell *lastCell = [tableView cellForRowAtIndexPath:lastSelIndexPath];
UIView *view = [lastCell viewWithTag:100];
[view removeFromSuperview];
You really need to look into subclassing UITableViewCell if you want a custom selection UI. Then override [UITableViewCell setSelected:animated:] (or [UITableViewCell setHighlighted:animated:]) to perform your customisations.
I have a UITableView with several UITableViewCells and inside these cells are UITextFields. I implemented a UIToolbar for switching between the different textfields. I can go to the next textfield in the next cell or to the previous textfield. This works fine until a cell should become first responder which is currently not visible in the tableview.
I figured out that
[self.tableview cellForRowAtIndexPath:indexPath]
returns nil and that manually scrolling to the cell with the textfield, which should become first responder, removes the problem. Therefore I tried scrolling to the cell before changing it to become first responder.
I tried that with
[[self.tableView scrollToRowAtIndexPath:newIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
but unfortunately the tableview does not scroll to this cell but to all other cells. When I add a breakpoint to this line the problem doesn't occur. It also looks like the tableview is scrolling to the cell but then scrolls down again.
Here is the code of cellForRowAtIndexPath:
UITableViewCell *cell;
static NSString *AttributeCellIdentifier = #"AttributeCellIdentifier";
cell = [tableView dequeueReusableCellWithIdentifier:AttributeCellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"AttributeCell" owner:self options:nil];
cell = attributeCell;
self.attributeCell = nil;
UITextField * textField = (UITextField *)[cell viewWithTag:1];
[textField setKeyboardType:UIKeyboardTypeDecimalPad];
[textField setInputAccessoryView:[self inputAccessoryView]];
}
UITextField * textField;
textField = (UITextField *)[cell viewWithTag:1];
textField.placeholder = #"C(Probe)/mol/l";
return cell;
Here is the code for switching to the previous textfield:
UIView * currentResponder = [self.view findFirstResonder];
UITextField * newFocusTextField;
UITableViewCell * cell = (UITableViewCell*)[[currentResponder superview] superview];
NSIndexPath* indexPath = [self.tableView indexPathForCell:cell];
newFocusTextField = (UITextField*)[[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]] viewWithTag:1];
[currentResponder resignFirstResponder];
[newFocusTextField becomeFirstResponder];
UITableViewCell * newCell = (UITableViewCell*)[[newFocusTextField superview] superview];
NSIndexPath * newIndexPath = [self.tableView indexPathForCell:newCell];
[self.tableView scrollToRowAtIndexPath:newIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
Hope this helps.
The code on your post and the problem definition is not hundred percent clear, but there was a bug/glitch in scroll methods' working for iOS 3.0 (i guess specifically 3.0, as far as i remember). I couldnot figure out the reason for it to happen, but it was crashing all the time, although it was OK for iOS 4.x.
The fix was adding a
[table reloadData]
before the scroll line. I know it doesnt make sense, and I know it is not good practice especially if the cell rendering is expensive, but it did solve the problem for that case. I dont know if your problem stems from the same issue, but you may just give it a try...
I tried several thinks and everything works now fine. I removed:
[currentResponder resignFirstResponder];
And after removing that line the tableview scrolled fine and I can directly set the pointer to the new cell with the newFocusTextField and make it firstResponder with:
[newFocusTextField becomeFirstResponder];
I have a nextTextField method which works fine with
[currentResponder resignFirstResponder];
so I don't really understand why the problem occurs but I think scrolling to the cell and then just setting the new firstResponder is better then resigning the currentResponder first.
Thank you for helping anyway ;)
How can one change the textLabel or the detailTextLabel of a specific UITableViewCell dynamically?
Basically, I am downloading a set of files from the internet whenever the user taps on a cell. Now instead of the progress indicator, I would like to display the name of the file currently being downloaded. I would like to keep updating the detailTextLabel to show the (current) filenames until all the files are downloaded.
Assuming you're in a method like tableView:didSelectRowAtIndexPath: (or have another way to get the index path to the cell), you can do something like this:
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
UILabel *label = nil;
for(UIView *subview in cell.contentView.subviews) {
if([subview isKindOf:[UILabel class]]) {
label = (UILabel*)subview;
break;
}
}
if(label)
label.text = #"New text";
This will find the first UILabel in the cell, and may not work if your cell has more than one label. A more robust way to do it is to set the tag of the label when you create the cell (this can be done in Interface Builder or in code). Then you can find the label like this:
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
UILabel *label = nil;
for(UIView *subview in cell.contentView.subviews) {
if([subview isKindOf:[UILabel class]] && [subview tag] == kDetailLabelTag) {
label = (UILabel*)subview;
break;
}
}
if(label)
label.text = #"New text";
Just in case anyone still has this problem I have had success with calls to the reloadData method. For example in my code in the viewWillAppear method, I have the line:
[tableSettings reloadData];
Where tableSettings is the name of my UITableView.