For some reason, I'm having trouble with making a textfield the first responder.
I have a UITableView with two rows. Each row has a label and a UITextField. The textfields are tagged kLoginRowIndex = 0 and kPasswordRowIndex = 1. As you might have guessed, I use this for setting login and password.
If the user taps on the return button when editing the login textfield, I want the password textfield to get the focus. Unfortunately, the password textfield doesn't accept the focus. Here is my code:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
NSLog(#"%s:(textField.tag:%d)", __FUNCTION__, textField.tag);
[textField resignFirstResponder];
if(textField.tag == kLoginRowIndex) {
UITableViewCell *cell = [self tableView:self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:kPasswordRowIndex inSection:0]];
UITextField *nextTextField = (UITextField *)[cell viewWithTag:kPasswordRowIndex];
NSLog(#"(nextTextField.tag:%d)", nextTextField.tag);
NSLog(#"canBecomeFirstResponder returned %d", [nextTextField canBecomeFirstResponder]);
NSLog(#"becomeFirstResponder returned %d", [nextTextField becomeFirstResponder]);
} else {
[self validate:textField];
}
return NO;
}
This is the log output:
-[SettingsViewController textFieldShouldReturn:]:(textField.tag:0)
(nextTextField.tag:1)
canBecomeFirstResponder returned 1
becomeFirstResponder returned 0
What I tried:
returning YES instead of NO
removing the call to canBecomeFirstResponder (which is just for debugging purposes)
Any hints are appreciated!
After playing with the suggestion of tmadsen, I found the error. The mistake is this line:
UITableViewCell *cell = [self tableView:self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:k
It returns a new cell, not the one currently on the screen. I replaced it with
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:kPasswordRowInde
and now it works as expected.
On a side note, I found out that 0 is the default value for the tag property, so it's probably not so clever to use it.
0 is the default value for the tag property so you'll probably want to use something other than 0, otherwise you will most likely return the superview when you call viewWithTag:
It's been a while since I developed for the iPhone, and I have never used the tag that you show in your code. But you can do what you want by making the textfields properties of your class. If you do that, and let's say you name those properties loginTextField and passwordTextField, then you can let the next textField be focused as follows:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if([self usernameTextField] == textField) {
return [[self passwordTextField] becomeFirstResponder];
}
else {
// your validating code...
}
return NO;
}
But as I said, it's been a while and I don't know this tag-thing you talk about, so maybe it's some new best practice, but the above code should be working
Related
I have a grouped table view that contains 3 sections and each row per section. The first two section rows contains UITextField(Name & Subject are the section titles) and the last one contains UITextView(Message is the section title) because i want to get some data from the user by this controller itself.
The two text fields have the returnKeyType as UIReturnKeyNext. For UITextView, the "return" button is present in keyboard to feed new line. So i used textFieldShouldReturn method to navigate to the next cell by pressing these return type buttons in UIKeyboard.
The next button will work fine with the first text field(Name). Here the problem comes... If i click the Next button of second cell, It goes to the UITextView(last cell) with one line down. That is, the cursor moves one line apart from its original position.
My code is...
-(BOOL) textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
if (textField == nameTextField) {
[subjectTextField becomeFirstResponder];
}
else if(textField == subjectTextField) {
[messageTextView becomeFirstResponder];
}
return YES;
}
What should i do to make this work fine? Thanks in Advance..
While testing a lot of stuff I found a simple yet suitable solution:
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
if ( [textField isEqual: nameTextField] )
{
[nameTextField resignFirstResponder];
[messageTextView becomeFirstResponder];
return NO;
}
return YES;
}
It handles the resigning of the nameTextField itself and returns NO to the request.
Basically what is happening is that when return is tapped you make text view the first responder and the return gets added to the text view. Thats why the cursor goes to the second line. Try doing this in your textViewDidChange: delegate method:
- (void)textViewDidChange:(UITextView *)textView {
if(textView.text == #"\r") {
textView.text = #"";
}
I've spent some time searching for this answer on SO, but couldn't find it, so here goes:
I'm starting with an ABPeoplePickerNavigationController, and when a user taps a person, they'll be taken to an ABPersonViewController where they'll be able to select phone numbers and email addresses. After they're finished with the ABPersonViewController, they'll be taken back to the ABPeoplePickerNavigationController. Pretty simple stuff.
What I want is to add a detailLabel to the table cell they selected in ABPeoplePickerNavigationController after they chose a phone number or an email address. Something like "Email and phone number chosen" or "Phone number chosen".
Apple's documentation says:
You should not need to subclass these controllers; the expected way to modify their behavior is by your implementation of their delegate.
The delegate methods provided won't handle this. Is there any way to accomplish this without subclassing myself? And, if I do have to subclass ABPeoplePickerNavigationController, which method would I override to update the detailLabel?
Thanks!
This bit of code seems to work for me, it grabs the cell when the user selects a person and adds a check mark. I'm guessing you can tweak the cell in other ways at this point as well.
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person{
UIView *view = peoplePicker.topViewController.view;
UITableView *tableView = nil;
for(UIView *uv in view.subviews)
{
if([uv isKindOfClass:[UITableView class]])
{
tableView = (UITableView*)uv;
break;
}
}
if(tableView != nil)
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:[tableView indexPathForSelectedRow]];
if(cell.accessoryType == UITableViewCellAccessoryNone){
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else{
cell.accessoryType = UITableViewCellAccessoryNone;
}
[cell setSelected:NO animated:YES];
}
return NO;
}
I have idea of how to do it, i think it will be helpful to you , but never implemented like this.
First you have to go with custom table . For that table you can give all the contact names from your addressbook. you can use http://developer.apple.com/library/mac/#documentation/userexperience/Reference/AddressBook/Classes/ABAddressBook_Class/Reference/Reference.html
just go through it you can understand .
you have to use these methods.
1) - (NSArray *)people
you will get all people records into returned array. each record will have unique id , you have to retrieve it
ABRecord rec = [returnedArray objectAtIndex:0];
NSString *pid = rec.uniqueId
-(NSString *) uniqueId ( this is ABRecord property method )
once you got it you can retireve from your array what you want by using that recordid/ unique id .
when pressing a row delete button on a table view, I do some validation, and if the user chooses to cancel the operation it all should rollback. Not only want to keep that row (what is happening), but also make disappear the delete button leaving only the "-" round button. How can I do that?
once again, thank you.
Assuming you are implementing your validations in tableView:commitEditingStyle:forRowAtIndexPath: method of your UITableViewDatasource protocol object, you should be able to set the editingAccessoryType and editingAccessoryView on the cell.
//After validation fails....
UITableViewCell *aCell;
aCell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
// validations are done and you need to ignore the delete
if ( aCell.showingDeleteConfirmation ){
aCell.editingAccessoryView = nil;
aCell.editingAccessoryType = UITableViewCellAccessoryNone;
}
If you want, you can wrap the changes in an animation block to animate the change.
Alternatively, you could toggle the editing state of the cell.
//After validation fails....
UITableViewCell *aCell;
aCell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
if ( aCell.showingDeleteConfirmation ){
aCell.editing = NO;
aCell.editingAccessoryView = nil;
aCell.editing = YES;
}
I am trying to get a string value out of a textField when the user dismisses the keyboard. However, it seems that whenever I try to get the value, I get garbage (attempting to print out textField.text gives out garbage). What could I be doing wrong?
(The control displays fine, and I can put text values into it even).
Here's my code:
-(BOOL)textFieldShouldReturn:(UITextField *)textField {
NSInteger currenttag = textField.tag;
NSLog(#"%d",textField.tag);
if (currenttag == 0) {
NSLog(#"%x %s",(unsigned int)textField.text,textField.text);
username = textField.text;
} else if (currenttag == 1) {
password = textField.text;
}
[textField resignFirstResponder];
return YES;
}
The fields username and passwords are nil NSString*'s, but since I will merely hold on to the NSStrings held by textField.text, it should be fine.
NSLog(#"text field text:%#",textField.text);
Have you tried using breakpoints? Have you tried NSLog(#"%#", textField.text); ?
Have you tried rewriting the function so it only displays the text?
Is the textField a valid object?
Inserting [textField retain]; as the 1st line will probably fix the problem. Just remember to add a [textField release]; at the end of the method.
I have a UITableView that has a disclosure button on every row. When the table is put into edit mode and the the Deletion control is pressed ("-" sign), the Delete Button shows, however the disclosure button is not replaced, but instead just slides to the left of the delete button.
The apple UITableView guide explains the delegates for everything it seems except for the delegate that is called when the "-" sign is pressed, but before the delete button is displayed.
I would just like to suppress the disclosure indicator while the delete button is shown.
I'm guessing that I am missing something... I have set the setHidesAccessoryWhenEditing:NO
on the cells of the table so that the indicator is displayed to indicate to the user that if they select the row, they can edit it...
The behavior I am trying to copy is done in the contacts app when a contact is edited. Any help would be greatly appreciated...
Thanks, Greg
The standard way to do this is to use cell.hidesAccessoryWhenEditing = YES, and that editing is a modal action in which navigation is typically disabled.
The Contacts application actually uses custom table cells, and I wouldn't be surprised if it didn't so much use an accessory as have an image located on the cell's right edge, judging by its behaviour.
If you want to know when the delete button appears, I'd suggest that you try installing a Key-Value observer on the cell's showingDeleteConfirmation property, like so:
[cell addObserver: self forKeyPath: #"showingDeleteConfirmation"
options: NSKeyValueObservingOptionNew context: NULL];
Then you implement the observer callback method:
- (void)observeValueForKeyPath: (NSString *) keyPath ofObject: (id) object
change: (NSDictionary *) change context: (void *) context
{
if ( [keyPath isEqualToString: #"showingDeleteConfirmation"] )
{
UITableViewCell * cell = (UITableViewCell *) object;
BOOL isShowing = [[change objectForKey: NSKeyValueChangeNewKey] boolValue];
if ( isShowing == NO )
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
else
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
I should note that I'm not sure whether the UITableViewCell class is KVO-compliant for this property, but it's got to be worth a try…
Or when you are creating your cell you can define the accessory type: cell.editingAccessoryType = UITableViewCellAccessoryNone;
The disclosure indicator is managed by tableView:accessoryTypeForRowWithIndexPath: so maybe you could change the accessory type while in editing mode.
I believe there's a tableView:accessoryButtonTappedForRowWithIndexPath:, maybe there you can note that you're going to edit mode and then change what the tableView:accessoryTypeForRowWithIndexPath: returns for each row - no accessory when in edit mode.
I would give it a try.
Here is a calling sequence (not sure if that helps) description/tutorial/examples from Apple reference about how to go about Inserting and Deleting Rows in Editing Mode.
My comment to Jim's solution didn't come across very well... Here is the version that solved the problem for me... Thanks again Jim!
- (void)observeValueForKeyPath: (NSString *) keyPath ofObject: (id) object
change: (NSDictionary *) change context: (void *) context
{
UITableViewCell * cell = object;
if ( [keyPath isEqualToString: #"showingDeleteConfirmation"] )
{
BOOL isShowing = [[change objectForKey: NSKeyValueChangeNewKey] boolValue];
if ( !isShowing )
{
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
}