G'day guys, I'm building an application that allows users to rapidly input numbers into a UITableView.
I've currently built the framework, but I'm having a bit of a hitch hooking up the view to have the keyboard load and make the text in the cell editable from a user action.
I remember there being an iOS example in the dev code somewhere, (like a year ago so it wouldn't be under NDA) where you added items in and edited them within the context of the UITableView without going to a detailed subview.
Just need a hint on how to hook up the delegates, or how to structure the code.
I have code where I create custom cells for a UITableView which have UITextField and UITextView controls on them. In the UITableViewController code I do this:
Interface
#interface MyTableViewController:
UITableViewController <UITextFieldDelegate, UITextViewDelegate> {
....
}
Implementation
-(UITableViewCell *) tableView:(UItableView *) tableView
cellForRowAtIndexPath: (NSIndexPath *) indexPath {
....
UITableViewCell * cell = ....
cell.myTextField.delegate = self;
cell.myTextField.tag = 1; //This should be unique.
return cell;
}
-(void) textFieldDidEndEditing: (UITextField * ) textField {
// Decide which text field based on it's tag and save data to the model.
}
-(void) textViewDidEndEditing: (UITextView * ) textView {
// Decide which text view based on it's tag and save data to the model.
}
You can add a UITextField or UITextView to any cell. If you have custom cells, make them a delegate for their text view, or if you compose the cells in your table view delegate, then make this the text fields' delegates.
Related
I have a UITableView of 'people' for my iOS app. I have created an 'add' screen to add new people to my persistent store, which works perfectly.
This add view uses a form created with a UITableView and subclassed UITableViewCells, with a UITextField and UILabel, which although works well, I am very new to iOS programming and feel that this may not be the most efficient way.
I am trying to re-use this add view to be my detail, add, and edit view, and I can successfully set a 'Person' entity as a property in the detail view. I have the following code in my viewDidLoad method, where the adding property is set in the prepareForSegue method in the previous ViewController :
if (self.adding)
{
self.editing = YES;
self.title = #"Add Person";
}
else
{
self.title = self.person.name;
[self setDetail];
}
My problem is that when I try to pre-populate my detail view's fields (my setDetail method), I am unable to set my UITextField text with the name property from my person entity. Here's the code I'm using to retrieve the UITextField and set it's text property with:
form is the UITableView;
UITableViewCell *nameCell = [form cellForRowAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
UITextField *nameField = (UITextField *)[nameCell viewWithTag:100];
nameField.text = self.person.name;
If I NSLog nameCell it returns (null)
I hope that's enough explanation. Any pointers would help a lot!
Instead of setting in viewDidLoad:, do it in your table view data source methods. i.e
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Deque the nameCell and prepare the cell if its not available.
UITextField *nameField = (UITextField *)[nameCell viewWithTag:100];
nameField.text = self.person.name;
return nameCell.
}
I don't really understand your question, but cellForRowAtIndexPath may return nil because
Return Value
An object representing a cell of the table or nil if the cell is not visible or indexPath is out of range.
Official Document: cellForRowAtIndexPath:
So I have looked around a quite a bit, and nothing on here seems to explain exactly the correct way of doing this. I have 7 UITextFields within a custom UITableViewCell.
My question is this: What is the correct way of managing the delegate of these UITextFields?
Since the custom cells are technically part of the "model" portion of the project, I would rather have the controller that controls the UITableView also control the text fields in the table's cells, but I can not figure out how to set the delegate for the text fields (which are created in the subclass of UITableViewCell) to this view controller.
Would it be bad practice to just make the subclass of UITableViewCell conform to UITextField delegate and manage all of that stuff in there? If so, how else should I go about doing this?
Thanks, any help would be appreciated.
You shouldn't have a problem setting the delegate of the cell's text field to be your view controller.
This is what you need to do:
1) The view controller needs to implement the UITextFieldDelegate protocol
2) Declare a property for the text field in your custom cell
#property (nonatomic, retain) IBOutlet UITextField *textField;
3) Then set the view controller as the text field's delegate in the method cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Cell";
MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
// use this if you created your cell with IB
cell = [[[NSBundle mainBundle] loadNibNamed:#"MyCustomCell" owner:self options:nil] objectAtIndex:0];
// otherwise use this
cell = [[[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
// now set the view controller as the text field delegate
cell.textField.delegate = self;
}
// configure cell...
return cell;
}
In my opinion the cell should manage the keyboard since it is the one that is holding the UITextField. You can set your cell as the UITextField delegate. In my own application, I have done this and then made my cell have it's own delegate. Any of the methods of UITextField or any new methods that should be handled by the controller can be passed along to the controller through the cells delegate.
In this way the cell can still be generic without knowing anything about what the application is actually doing.
My suggestion would be to "tag" (i.e. set the tag) of each textField with a value that encodes the section, row, and one-of-7 text views in the table, then make the UIViewController the delegate.
So you need to bound the size of these - say you will never have more than 100 rows. So you encode this as:
.tag = 1000*section + 100*row +
When you get a message you can have a method/function take the tag and decode it into section, row, tag, and do what you need to have done.
To declare your TableViewController as the delegate include <UITextFieldDelegate> at the end of your #interface in the TableViewController's .h file.
#interface MyTableViewController : UITableViewController <UITextFieldDelegate>
Then, connect the text fields by ctrl-dragging each field under the #interface. Each UITextField is connected to its respective property by an IBOutlet. Finally, in the .m file include the following function to show the delegate which field you want to return....
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[aTextField resignFirstResponder];
return YES;
}
Swift version (Based on Eyal's answer)
class MyViewController: UIViewController, ... , UITextFieldDelegate {
#IBOutlet var activeTextField: UITextField! //doesn't need to connect to the outlet of textfield in storyboard
....
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
....
var cellTextField = self.view.viewWithTag(101) as? UITextField
cellTextField!.delegate = self;
....
}
In my App I have a ParentViewController that have several elements in it. One of the elements is a UITableView.
I designed the table's cells using a Dynamic Prototype Cell that I had designed within the Storyboard.
Meaning, that I have in the Storyboard a UIViewController; inside it I have a UITableView; and inside the UITableView I have a Prototype Cell.
Now, I added a UIButton inside the the Prototype Cell, created another UIViewController (let's call it ChildViewController) and connected the UIButton and the ChildViewController within the Storyboard with a Segue.
How should I write the code that activates the Segue when the user clicks the UIButton?
I managed to create the table itself and have data inside the Dynamic Cells (they have some UILabels aside to the UIButton), but I cannot figure out how to connect the UIButton to the code properly.
I don't want to use the UITableView default "select" features, since I wish to have several buttons inside the Dynamic Cells - each one will derive a different segue to a different ChildViewController.
Here's how I solved the same problem. Hope it will help.
To do this, you can pass the pointer to your UITableViewController to your custom cell's initialization method, and store it there:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// ...
CDTrackCell *cell = [tableView dequeueReusableCellWithIdentifier:strCellTableIdentifier];
CDTrack *currTrack = [self.fetchedResultsController objectAtIndexPath:indexPath];
[cell configureView:currTrack inTableViewController:self];
return cell;
}
Save the pointer in custom UITableViewCell class:
- (void) configureView:(CDTrack*)track
inTableViewController:(CDTracksViewController*)_tvc
{
self.tvc = _tvc;
// ...
}
Then, you can perform a segue when the button is tapped:
- (IBAction)buttonAddToTracklistTapped:(UIButton *)sender {
[self.tvc performSegueWithIdentifier:#"showAddToTracklist" sender:self];
}
Any better ideas?
So I thought I'd have a go at building my own simple app. Please go easy on me I'm new to all this! The idea is this. For iPad have a single view controller with a text box and a text field. Text box takes a title, and text field takes the body of a report. There's a button on the page to submit the report, which bundles the two texts into an object and adds it to a table view within the same view controller. I have set the view controller as a delegate with <UITableViewDelegate, UITableViewDataSource> in my header file. My table view works fine for adding items in the viewDidLoad method. But adding items from the text inputs via a UIButton connected to -(IBAction) addItem falls over with: Property 'tableView' not found on object of type 'ReportsViewController'
- (IBAction)addReportItem
{
int newRowIndex = [reports count];
ReportObject *item = [[ReportObject alloc] init];
item.title = #"A new title";
item.reportText = #"A new text";
[reports addObject:item];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:newRowIndex inSection:0];
NSArray *indexPaths = [NSArray arrayWithObject:indexPath];
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
}
I understand that I'm trying to call a method within my object but I have other method calls to tableView which work fine. i.e.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [reports count];
}
I thought this was the point of delegation. I know I'm missing something, but as I say I am new to all this and have looked everywhere for an answer before posting. What do I need to do to send my IBAction message to tableView?
Do you have a tableView instance variable setup in your .h file of the view controller?
The reason you are able to access it in the delegate and data source methods is because they are passed in as part if the methods.
You will need to add the IBOUTLET tableView ivar and connect it to the tableView in your .xib.
Or perhaps your ivar for the tableView is named something else?
Good luck.
I had the same problem.
What helped was to inherit the View Controller from UITableViewController, instead of UIViewController. Not using the protocol names in angled brackets.
The TableView is then linked to the dataSource and delegate via the storyboard (resp. InterfaceBuilder).
The parent class UITableViewController has an IBOutlet tableView defined.
MyViewController.h:
#interface MyViewController : UITableViewController
I have a view which contains a tableview, (i call this view the EquationView, and its controller the EquationViewController). The table view cells are custom cells with a label and a textfield, representing a variable and its value, receptively. I have been able to get my custom keyboard to apear when editing begins in the textfield.
However, I haven't been able to get the keystrokes to apear in the correct cell, do to the fact that I haven't been able figure out how to send the indexPath of the cell with textfield being edited to the custom keyboard controller class. I have included my EquationViewController.h file in my custom keyboard controller class and have been able to change the text in the tableview's textFields by manually setting the indexPath to a specified row. Here is the keyboard class definition:
#import <UIKit/UIKit.h>
#import "EquationViewController.h"
#interface CustomNumberPadViewController : UIViewController {
EquationViewController *equationViewController;
}
#property (nonatomic, retain) EquationViewController *equationViewController;
-(IBAction)buttonPressed:(id)sender;
#end
My action method looks like this (so far):
-(IBAction)buttonPressed:(id)sender{
VariableCell *cell = (VariableCell *)[equationDetailViewController.myTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
cell.variableValue.text = #"test";
}
This get the word "test" to appear on whichever row I set in the index path.
So what I'm wondering is, is there a way to pass/get the indexPath of the cell whose textField is being edited to the action method in my custom keyboard controller class?
Why don't you set your UIViewController as the delegate of your UITextFields and catch the textFieldDidBegin: delegate method?