Fetching invisible uitableviewcell - iphone

I have a tableview with each cell loaded from a xib. It is in the format UILabel some space and UITextField. On a button click somewhere on the view I need the action to fetch all the textfield values in the UITableView with the labels in a dictionary. The problem is when I alloc a cell and fetch the values from there using indexPath, the code crashes exactly at the indexPath of the cell which is invisible (out of screen bounds).
I would appreciate any good ideas on how to fetch those cells which are not visible on screen.
Thanks!

UITableViewCells are reused when they scroll out of view, so that's probably why it won't let you access attributes of UITableViewCells that are not visible.
An NSDictionary might be your best bet:
Set a tag for each cell's UITextField based on the indexPath.row value during cell creation.
Set the delegate for each UITextField to your view controller.
In the delegate method textFieldDidEndEditing, update your dictionary as such: [dictionary setObject:textField.text forKey:[NSNumber numberWithInt:textField.tag]]
And now you can access an array of your textField values with [dictionary allValues].

Related

How to have an editable multine UITextView in UITableViewCell

I've got a UITextView inside a UITableViewCell subclass. I have no problem getting the new height of the Text view and cell. The problem I have is telling the UITableView to update.
I have implemented heightForRowAtIndexPath: to return the live height of the cell as the TextView expands.
But somewhere `[tableView beginUpdates]; [tableView endUpdates]; must be called.
How? Should I add a delegate property to the UITableViewCell which is set to the UITableViewController subclass? And then send a delegate message when the cell expands height and the Tableview needs to update? It seems a little weird to have a delegate between the UITableViewCell and Controller?
I tried using NSNotificationCenter, but I have more than one editable cell, and more than tableview of this nature. So there is no way to register only for notifications for the cells without copying and pasting the same line over again, which isn't nice (as the cells are created in IB, and are not in an array or set), and having multiple tableviews means an exception occurs on the other table view as it is told to update but nothing changes.
I've seen lots of questions and answers on this topic, but when it comes to updating the tableview they all just say "now update the tableview" and not how to. So how do I telly he tableview to update, from one of it's cells?
I would think that this behavior would be best implemented in the UITableViewController instead of the view itself (the UITableViewCell).
Your controller is responsible for setting cell height, and typically will be the delegate for your UITextView's, so let it handle all of this.
In your textViewDidChange method, figure out what the new height of your cell should be, update your data structure to reflect that, and call reloadRowsAtIndexPaths:withRowAnimation: to have it actually change.
Edit:
So since you didn't like my first suggestion, another way to do this would be to add a recommendedRowHeight property to your custom UITableViewCell.
Then, you can either observe this property from your UITableViewController or implement a delegate protocol with a method along the lines of:
- (void)recommendedRowHeightDidChange
// or
- (void)recommendedRowHeightDidChangeTo:(CGFloat)newHeight
Then, when your height changes, update your recommendedRowHeight property and call your delegate's method if you go that route.
Either way, once your controller figures out that the recommended row height of a cell has changed, it can do what it is supposed to do. Update your data structures reflecting the current row heights and then call reloadRowsAtIndexPaths:withRowAnimation:.
You can add your tableview controller object as a weak reference to your tableview cell class. And in tableview controller you can have a method which will be called from tableview cell class.

Adding UIPickerView to a UITableViewCell

I want to add a UIPickerView to a UITableViewCell. Right now I am just getting a black window. Can someone also explain me the concept of subclassing UI objects to a cell ie:when do we make our cell as the delegate and the datasource delegate? Thanks
EDIT: Here is the code of what i am doing right now
case 1: {
cell = [tableView dequeueReusableCellWithIdentifier:#"groups"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"groups"];
}
/*NSString *myGroupDetail = [_groupArray objectAtIndex:indexPath.row];
NSLog(#"the group detail label is %#",myGroupDetail);
cell.textLabel.text = myGroupDetail;
*/
[cell addSubview:_groupPicker];
break;
}
The groups is the section in which I want the picker view, I am getting that data from an array.
you would have to allocate and initialize a pickerview in your cellForRow method of the tableviewdelegate. ill sketch it for you =) how to initialize a cell itself should not be hard to find out if you google a bit ;-)
...(tableView *)... cellForRowAtIndexPath... {
if(indexPath.row == pickerRow){
UIPickerView *pickerView = [[UIPickerView alloc]init];
cell = ... // alloc and initialize a cell
cell addSubview:pickerView];
}
else{ // your other cells }
return cell;
}
UPDATE: im currently having trouble with git, so i uploaded a sample project to my private server: UITablePicker example
github: https://github.com/sebamisc/UItableViewWithPicker
yu can modify and use the code however you want =)
sebastian
Well, I never did exactly that.
Does it have to be in a cell or could you use the table's header or footer view for that? (I would not suggest a section header/footer view.)
Assuming it is within a UITableViewCell.
Yes, I personally would subclass UITableViewCell. Did that a lot. In that case you cell object could be the data source delegate of the picker. For doing so your subclass of UITableViewCell (let's assume you name it MyTableViewCell) needs to fulfil the related protocol. You add that UIPickerView programmatically within the init Method (initWithStyle) of MyTableViewCell. For the layout within the table cell, you should overwrite the method layoutSubviews. If your app can be rotated to landscape and portrait orientations and/or if your app is designed to run on iPad as well, then this method should dynamically consider the table's bounds. (Screen or windwo bounds are often used hiere but that is not save when the table is displayed within a split master view or a popup view on iPads.)
Strictly spoken your MyTableViewCell should not be the data source delegate, simply because it is a view element and view objects are not supposed to manage any business logic within an MVC design pattern. Smarter would be the implementation of some dedicated view controller for your table view cell hat fulfills the protocol and is assigned as the delegate. However, both would work. In the event that it is the only picker view within your sell, then you could easily use your UITableViewController subclass even without tagging the UIPickerView.
An alternative to subclassing a UITableViewCell is to create the UIPickerView within the cellForRowAtIndexPath method of your tableViewController. That is fine for singe-orientation apps. However, you may setup it in a way that it re-arranges its the UIPickerView automatically.
In any case you should overwrite the heightForRowAtIndexPath method of UITableViewController when your table views do not have the same hight any more. If all of them still have the same height, then you can simply set the rowHeight property of your UITableView.

how to center uitableview selection with indexpath value

I am saving the indexPath selection from a subview and passing it to the parent view with delegates. When I got back to my subview from my main view I pass the indexPath back to it and show the user which cell they previously selected with a tick in the accessory view of the tableviewcell.
One problem being if the user has selected a cell out of a fairly big list its hard to find the cell they selected again incase they wanted to change it (being that they made a mistake)
I would like to know if their is a way to use indexPath or something similar to center the previously selected cell of the uitableview to the center of the screen?
UPDATE::
Here is a graphical view of what I am trying to achive to make it abit more understandable..
step one : select cell then go to subview and select the cell (value) you want to pass back to main view (save indexPath of selected cell)
step two: user either wants to change his selection or made a mistake and was ment to select the cell below the one they chose... repeat previous steps but display previously selected cell in the center of the view..
Have you tried the following function
[tableView scrollToRowAtIndexPath: atScrollPosition:UITableViewScrollPositionMiddle animated:YES]
a UITableView is a subclass of UIScrollView - try setting the Content Offset (figure out how much with the cell height and indexPath).
[tableView setContentOffset:CGPointMake(0, indexPath.row*cellHeight) animated:YES];
should work. You might want to do the math a little differently.

Setting UIPickerView selection to UITextField inside a UITableViewCell

I have a UITextField in a custom tableview cell. On tapping the textfield area I display a popover which contains a pickerview. I need to set the selection from the pickerview to the textfield's text. I show the popover from the textDidBeginEditing method. How do I pass the selection from the pickerView's didSelect method to the textfield?
By design the entire thing is in a TableViewController with the textfield and pickerview delegate methods implemented.
Thanks!
Just set the UIPickerView's delegate to be the viewcontroller that has your UITableView. That way on the UIPickerView's didSelect (implemented in the tableview's viewcontroller) you would simply use the pickerview's datasource to populate the textfield.
To get your custom cell from a tableview you simply do:
CustomTableViewCell *thisCell = (CustomTableViewCell*)[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:section]];
Then you set the textfield in that to have whatever text you want:
thisCell.textField.text = #"text";
Can you provide a little more information? What's the tableView:cellForRowAtIndexPath: look like? I'm curious where the object you're editing is available.
There are a couple approaches I can think of...
Set the tag on the textField(s) and use it to locate the specific textField being edited
Set the delegate for the pickerView to the tableCell and have it handle the textual change
I believe the best approach is to set the UITextField's inputView property to a UIPickerView. This view will be displayed instead of the keyboard.
When a UITableViewCell is scrolled beyond a table's bounds, it may be deallocated. Therefore, storing a reference to the UITextField which invoked its textFieldDidBeginEditing: delegate method could result in an EXC_BAD_ACCESS exception.
The solution is to modify the cell's model which is stored in an array by the view controller. When the cell is initialized, it should set the text field's value to the corresponding value in its model object. Finally, the cell should observe changes to its model via KVO and update the value of the text field accordingly.

Change properties of UILabel in a TableViewCell

I have a tableView that's loosely based on the DetailViewController in ye olde SQLiteBooks. It's created programatically. Each cell displays a single value that when clicked displays a generic editingController that allows the user to edit that value. Pretty standard Cocoa-touch stuff...
Except...I also have a segmented control in the header of said tableView that depending on it's setting needs to change an attribute (textColor) on a UILabel in ONE of the 8± tableViewCells in the table. I have no IBOutlets for this tableView because I created it entirely in code. So, what do I need to do in my (void)segmentAction:(id)sender method (triggered when segmentedControl changes state) to allow me to access & change this value and display it to the user? When the table was built (cellForRowAtIndexPath) every UILabel was called "value" and then added: [cell.contentView addSubview:value].
I've tried setting a property of the viewController itself that is then checked during cellForRowAtIndexPath and does the textColor business there...and then adding [self.tableView setNeedsDisplay] to my segmentAction: method but it doesn't seem to work?!?
Any ideas?
If you know the indexpath of the cell you want to modify, you can call cellForRowAtIndexPath: to retrieve the UITableViewCell. Once you have that, you can get the UILabel from it. If you set the UILabel's tag to some useful value when create it, you can then retrieve it from the UITableViewCell via viewWithTag:.
In the class that implements cellForRowAtIndexPath you could also store a reference to the UILabel that you want when you build the relevant cell.
This would then mean you could alter the label and mark it to be repainted.
Alternately you could hold a local BOOL to show that the cell should be drawn differently - and then use this this in the cellForRowAtIndexPath: to draw it with a background.
You might find this easier with the 3.0 textLabel object in a UITableViewCell