Recognize tab button pressed to move to next responder - iphone

I have multiple instances of a custom class that takes inputs from keyboard. You can think of UITextField (but they are not UITextField, they are NSObject). However, they all have a property UIControl *control.
These objects are instantiated and put into an array (orders matter), and they are put on the screen in the same order.
Scenario 1: User tabs on the first object, it becomes the first responder. User taps on another object (from the same class) and that becomes the first responder. No problem.
Scenario 2: User tabs on the first object, it becomes the first responder. User taps on the TAB button of the keyboard (iPad or iPhone or wireless keyboard), I want the next object in the array becomes the next responder. iOS picks randomly [? or with some logic not clear to me] another object which is not in the same order as I want.
Problem: Because these objects are NSObjects, how can I intercept the transition to the next object. I tried using tags or tracking who is the first responder, but the problem is, if user taps on an object out of order, it is fine - I don't want to intercept that. I only want to intercept transition from one object to anther only if it is through tapping on TAB (or Next or Return) button of keyboard.
Any idea? Thanks.

You can set your custom class to have something like this
#interface testClassButtonSub : UIButton
#property (weak,nonatomic) IBOutlet UIButton *nextButton;
#end
Then you can even use the interface builder to set which will be the next responder for when a certain action is taken. (an user presses the return when inside a textfield in your custom class)
For the return you have to declare your viewcontroller as the delegate of the specific textview.
First you set the viewcontroller header like this:
#interface RegisterViewController : UIViewController <UITextFieldDelegate>
then you set the delegates in the implementation
// Set Delegates of the Text Fields
eMail.delegate = self;
userPassword.delegate = self;
userNickname.delegate = self;
and you use this delegate method to jump to the next object
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
// Jumping code here
return NO;
}
HOWEVER in your case your textfield must be inside your object, so you have to make THAT object the delegate, and in that object's implementation jumping code add the
[thisObjectsTextfield becomeFirstResponder];

Related

How to identify which textfield is currently first responder

If you have several text fields on the screen, and the keyboard pops up for each one when they are tapped, what if you want to programmatically hide the keyboard, or resign first responder, but you don't know which textfield to send the resignFirstResponder message to? Is there a way to identify which object/textField should get this message?
check all of your textfield call
[textfield isFirstResponder]
You could keep track of which text field is the first responder by either setting your view controller to be the delegate object of all text fields and then when your subclassed text fields gets the "becomeFirstResponder" method call, tell your view controller which text field is the current one.
Or, there's a more blunt force approach which is a category extension to "UIView":
#implementation UIView (FindAndResignFirstResponder)
- (BOOL)findAndResignFirstResponder
{
if (self.isFirstResponder) {
[self resignFirstResponder];
return YES;
}
for (UIView *subView in self.subviews) {
if ([subView findAndResignFirstResponder])
return YES;
}
return NO;
}
#end
which I got from this potentially very related question.
You Can Check Your all TextField and than Identify Easily.
[textfield isFirstResponder];
There is no public method to get the current first responder, but you can do things to still get it; The first one is obviously to keep track of this yourself. You can do this in various way and if you don't want to touch any existing class but just want it to work, a category and method swizzling will do the trick. The more cleaner solution however is to iterate through the view hierarchy and ask the views wether they are the current first responder. You can start with the root UIWindow and start iterating, or you can start with your current UIViewController's view, but keep in mind that the current first responder doesn't have to be part of your roots UIWindow view hierarchy (eg. if you have a text field inside an UIAlertView).
Try this (Swift 3):
if textField.isEditing {
textField.resingFirstResponder()
}

Call method when changing UITextField's directly

I'm currently developing an iPhone app where I have two UITextField's in one View Controller.
I have a method that is called when the keyboard appears (keyboardWillShow), and one that is called when it disappears (keyboardWillDisappear).
Now if the user touches the first field the keyboardWillShow method is called, but if he now touches the second field without touching the background before, keyboardWillShow of course is not called again, because the keyboard is already here.
I can also not use textFieldDidBeginEditing:(UITextField *)textField because it's also not called when you change field's directly.
Now how can i call keyboardWillShow again if he touches the first and the second one without letting the keyboard disappear between??
I found out the problem was i didn't set the delegate of the textfield's properly.
After setting #interface ViewController : UIViewController <UITextFieldDelegate>in my .h file and textfield2.delegate = self in the .m file, textFieldDidBeginEditing: was called when i changed the textfield's directly.

Double Picker Question

I want to display the contents of a double picker to a label without hitting a button in the process. Can anyone show me how this is accomplished.
I displaying calculations to a label and I want them to change as the user moves the picker.
You need to set up a UIPickerViewDelegate, set it as the delegate of your picker, and implement – pickerView:didSelectRow:inComponent: to modify your label how you want. The UIPickerViewDelegate protocol reference is here. I would probably just set the viewController for the containing view as the delegate, but it depends on how your program is structured.
EDIT - example code added:
You declare a class as implementing a delegate protocol with <> notation as in the following:
#interface MyViewController : UIViewController<UIPickerViewDelegate>
Then you can set the delegate of your picker view instance like so:
myPicker.delegate = myViewControllerInstance;
Or, if your picker is an ivar of the viewcontroller class:
myPicker.delegate = self;
Then, inside the implementation of your MyViewController class you can optionally implement the methods of the UIPickerViewDelegate protocol, and the corresponding messages will be sent at the right time. eg, -pickerView:didSelectRow:inComponent: (if implemented in your delegate) will be called whenever the picker selects a value, and it will be passed the row selected and the component the row was selected in.

Objective-C iPhone - Delegating an IBAction from one class to another? Can this be Done?

I have created a class, that makes it easy to enter in the amount for a particular price in the same way an ATM machine allows you to enter in an amount, user does not enter the decimal.
This is a generic class called (AmountPicker), so that it can be used among many other classes. I am using it by invoking the presentModalViewController method, this class uses a nib file. Inside the xib there is a hidden text field and a label along with a done button in the navigation bar. The done button is an IBAction connected to a method named doneButtonPressed.
I am wanting to know if it is possible to delegate this method to another class, so that the logic inside the method can differ from the one already defined inside the amountPicker class.
The reason is, I use the amountPicker Class in two places one for entering a purchase, which takes the label text and assigns the value to a variable inside the appDelegate, this was ok when i just used it in one class, but now there is a detailTableViewController of the purchase and this view will also need to provide a way to change the data in case it was entered wrong.
So in the detail view i am using a custom header, the custom header has a textField for the name of the purchase, a button to activate the AmountPicker, and a label for the amount, when the amount button is pressed then the AmountPicker class pops up and the user enters the amount and presses the done button, NOW, this is where i need to change the logic for the doneButton, instead of using a variable in the appDelegate.
I was thinking that the DetailTableViewController could act as a delegate for the amountPicker Class and override the doneButtonPressed method, so that the amountLabel can be updated with the new amount.
Is this possible, if not what is the right way?
Your thinking is right along with how delegation is normally used. What I would do is create an Objective-C protocol, maybe AmountPickerDelegate. Then, in your interface for the AmountPicker, you would have this:
#interface AmountPicker : NSObject {
NSString *someValue;
...
id <AmountPickerDelegate> delegate;
}
#property (assign) id <AmountPickerDelegate> delegate;
#end
Then, in your delegate class, you would do this:
#interface DetailTableViewController : UITableViewController <AmountPickerDelegate>
Finally, in the original AmountPicker class, you could call something like this:
[delegate amountPickerDidPressDoneButton];
which would execute in the delegate.

What is the easiest way to add a row in a UITableView with a user-provided string?

I have a simple UITableViewController in a UINavigationController that displays a list of strings from an array with the default Edit/Done button on the right-hand side of the navigation bar.
When pressing the Edit button, the UITableView animates correctly and shows the red minus icons to delete. Pressing the delete button removes the row from the table view and the array (implemented in the tableView:commitEditingStyle:forRowAtIndexPath: method of the UITableViewController).
I would now like to allow the user to add a row to the view (and add the string to the underlying array), but I'm not sure how to go about doing so. The commitEditingStyle method has else if (editingStyle == UITableViewCellEditingStyleInsert), but I don't know how I can get the user to input the string.
I've read the Table View Programming Guide (more specifically the example of adding a table-view row), but this seems to require a whole new UIViewController subclass just to get a string from the user.
Is there no easier way?
Creating another view controller is probably going to be the easiest way in the long run. You can present it modally by calling
SomeViewController* theViewController = [[SomeViewController alloc] init];
[self presentModalViewController: theViewController animated: YES];
[theViewController release];
When the theViewController is ready to go away it can call
[[self parentViewController] dismissModalViewControllerAnimated: YES];
OR
you can setup a protocol for your new view controller so it can notify your original view controller of completion and send a value back, if you wanted an NSString back you might use
#protocol MyViewControllerDelegate
- (void)myViewControllerDelegate: (MyViewController*)myViewController didFinishWithValue: (NSString*)theString;
#end
MyViewController would then have a delegate property
#interface MyViewController
{
id<MyViewControllerDelegate> delegate;
}
#property(nonatomic,assign) id<MyViewControllerDelegate> delegate;
#end
If you use the protocol method your original view controller will adopt that protocol and will dismiss the modal view itself when it receives this message.
I hope that helps out, it may seem a little complicated at first, but it makes gathering data very easy.
You could use a UIAlertView or similar class yourself. Just pop up the modal view to request the string, establish the right callbacks, then pop it in your dataSource.
You can also insert a cell with a UITextView and a "Tap to Edit" placeholder, then on the textView Callbacks, remove the textView and display the string. Further editing would need to drill down or do something else