Best practice for touch intention - ios

Consider a simple view with three or more UITextField subviews called "A", "B", "C", and so on. The view controller implements UITextFieldDelegate and has a textFieldShouldEndEditing that looks something like the following:
- (BOOL)textFieldShouldEndEditing:(EFFUITextField *)textField
{
return [self isValidSolution];
}
If the first responder is field A and the user taps field C, assuming field A passes the criteria in isValidSolution, field C will become the first responder.
Now consider the same situation but now we wish to prompt the user with an UIAlertController to allow them to override the invalid condition:
- (BOOL)textFieldShouldEndEditing:(EFFUITextField *)textField
{
if ([self isValidSolution])
return YES;
[self promptUser];
return NO;
}
Since UIAlertController is handled asynchronously, we will need to be able to detect that it was field C that the user tapped and make that the first responder.
What is the best practice for detecting which field the user meant to enter so that we can make it the first responder if the user chooses to override the validation discrepancy?

I would store whichever field you intend to resume editing in a property, then in your UIAlertController's completion block call becomeFirstResponder on that text field. You could even skip the property if you just capture the field to resume editing in your UIAlertController's completion block at the time it's created.

Related

iOS hiding keyboard on "Return" press, resignFirstResponder vs endEditing

I was searching for hiding the iOS keyboard when you press "return", and about half the answers are to use self.view.endEditing(true) and the other half textField.resignFirstResponder(). Is one a better way than the other?
For reference or anyone coming here from Google or something, you need to add UITextFieldDelegate to your class inheritance, add self.<your_TF_var_name>.delegate = self in viewDidLoad(), then make a function
func textFieldShouldReturn(textField: UITextField) -> Bool {
self.view.endEditing(true)
return false
//OR
textField.resignFirstResponder()
return true
In this case, it doesn't really matter which you use though technically, using textField.resignFirstResponder() is more efficient because you already know that is the text field you need to resign.
The call to self.view.endEditing(true) is going to have to figure out what the current first responder is and then call resignFirstResponder on it.
My general rule of thumb is to use resignFirstResponder if you have a reference to a specific view you wish to resign. And use endEditing if you don't and you just want the current first responder to be resigned.
On a side note, you should return false from textFieldShouldReturn in either case. There is an edge case where returning true can lead to a newline being added to a UITextView after resigning the UITextField. So as a rule I always return false.

Value of textfield before "Editing Changed" event is fired

I want to know if there is a way to know the value of textfield before the value is changed to the new value.
For example:
If the text field had a value "a" and the user entered "b", so the editing changed event is fired. When I try to fetch the value of the text field in the debugger it will display "ab". Is there a way that I can get "a" before "b" was written?
Here is a piece of code where I am trying to fetch the value:
#IBAction func commentEditingChanged(sender: AnyObject) {
if(!((sender as? UITextField)!.text!.isEmpty)){
counter++
}
else
{
counter--
}
}
In this case I want to know if the text was empty before the user entered text because I don't want the counter increments every time the user enters a character. I want to increment once the user entered any text.
And please don't propose to use delegate function textField:shouldChangeCharactersInRange:replacementString because my question is about this IBAction method.
If there is no way to do that using this IBAction Method, is there is any other IBAction method that can achieve what i want?

Why call method to resignFirstResponder from textFieldShouldBeginEditing?

I am trying to understand delegate methods in general, and specifically how to dismiss a UIDatePicker that popovers from a text field.
According to the documentation, textFeildShouldBeginEditing returns true 'if an editing session should be initiated; otherwise, false to disallow editing.'
Why would I then tell the app to resignFirstResponder, which is meant to hide the keyboard / date picker (as in several examples on stackoverflow and noobie tutorials)?
What I don't understand is: if it should begin editing, why then hide the input devise? Obviously, I am misunderstanding one or both concepts.
func resign() {
dobTextField.resignFirstResponder()
nameTextField.resignFirstResponder()
println("resign gets printed, but the date picker is still visible!?!")
}
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
if (textField === dobTextField) {
resign() // but should begin editing, oder?!?
}
In the examples you cite, the textField is being used to display a date. When the user selects this field, the app designers want the UIDatePicker to be displayed instead of the keyboard. Hence they call resignFirstResponder to hide the keyboard. At the same time, they display the date picker.
ResignFirstResponder will not hide the date picker, so the "input device" (for this field) will still be available.
Also, note that in one case the developer has used textFieldShouldBeginEditing, and returns false because they are providing the date picker. In the other case the developer uses textFieldDidBeginEditing (which has no return value).
you should resign only the textfield not affected:
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
if textField == dobTextField {
nameTextField.resignFirstResponder()
} else if textField == nameTextField {
dobTextField.resignFirstResponder()
}
return true
}
this way you are resiging first responder only on the textfields that should not currently be edited. this helps if for some reason you accidentally have 2 textfields (or more) assigned first responder causing conflicts with multiple keyboards/datepickers and such.

dynamically change UIKeyboards return key

I have two UITextfield the user enters his name into the first and email into the second. I would like to know how to change the UIKeyboards return key depending if the name text field has an entry or not.
For instance if nametextfield is empty then I would like the UIkeyboard return key to be Next
else if the nametextfield has an entry in it then when the user selects the email text field I would like the return key to be submit.
Is this possible? if so how would I go about accomplishing it? any help would be appreciated.
You can have return key customized to prefixed values that you can see in UIReturnKeyType enum for each UITextField.
textFieldName.returnKeyType = UIReturnKeyNext;
textFieldEmail.returnKeyType = UIReturnKeyDefault;
Not sure if this is what you're looking for though.
You have a chance to set up keyboard characteristics in the UITextFieldDelegate Protocol method textFieldShouldBeginEditing: which is called before the text field becomes the first responder (indeed to decide if it may become the first responder). If you don't already have a delegate for the text field(s) in question you would have to assign one and implement at least that method. Presumably the same object handling the text field could hold the delegate methods. The following implementation sets the return key to "Search".
- (BOOL) textFieldShouldBeginEditing:(UITextField *)textField {
NSLog(#"textFieldShouldBeginEditing");
textField.returnKeyType = UIReturnKeySearch;
return YES;
}
You'd have to look at the contents of your text fields to decide what value to use.
Make use of the textField.returnKeyType property.
you can check out all the available options here http://developer.apple.com/library/ios/documentation/uikit/reference/UITextInputTraits_Protocol/Reference/UITextInputTraits.html#//apple_ref/doc/c_ref/UIReturnKeyType
textfield.returnKeyType = UIReturnKeySearch;

iPhone/iPad: How to make UITextField readonly (but not disabled)?

I understand this question has been asked before, but I'm not satisfied with the answers, i.e. by making it disabled. There is a fundamental difference: Disabled view doesn't fire events, but for a read-only view, it should still fire event like (e.g. TouchUpInside), and I need it. Only thing I don't want is the keyboard input.
The reason is that I have several input fields, some can useUITextField directly, others are not. I want to have them look similar. So, I'd like to use UITextField to display all of them. Some of them need to be read-only so that I can use touch up event for alternative input.
Or there might be a completely different way to do it?
EDIT: This is for my MonoTouch project. I have very limited knowledge of Objective-c.
Say you have 2 text field instance variables connected to text fields you created in the Interface Builder. Lets call them myReadOnlyTextField and myEditableTextField. Make sure you connect the delegate property of each text field in the Interface Builder to the view controller ("File's Owner")[1]. Now, in the view controller #implementation (.m file), use the method textFieldShouldBeginEditing: and put in some logic to determine which text field you want to allow editing and which to not allow editing; something like this:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
BOOL editable;
if (textField == myReadOnlyTextField) {
editable = NO;
} else if (textField == myEditableTextField) {
editable = YES;
} else {
// editable = YES/NO/Other Logic
}
return editable;
}
From the UITextFieldDelegate Documentation:
textFieldShouldBeginEditing:
Asks the delegate if editing should begin
in the specified text field.
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
Parameters
textField - The text field for which editing is about to
begin.
Return Value
YES if an editing session should be initiated;
otherwise, NO to disallow editing.
Discussion
When the user performs an action that would normally
initiate an editing session, the text field calls this method first to
see if editing should actually proceed. In most circumstances, you
would simply return YES from this method to allow editing to proceed.
Implementation of this method by the delegate is optional. If it is
not present, editing proceeds as if this method had returned YES.
UITextField Documentation is a good read also.
[1] You can do this programmatically as well. Here is an example:
- (void)viewDidLoad {
[super viewDidLoad];
// .....
myReadOnlyTextField.delegate = self;
myEditableTextField.delegate = self;
}
Despite the fact you need no keyboard, textField:shouldChangeCharactersInRange:replacementString: is very useful. It prevents text field from editing but still leaves it selectable in contrast to textFieldShouldBeginEditing:.
In monotouch:
var txt = new UITextField();
txt.ShouldChangeCharacters += (field, range, replacementString) => false;
You can have two options:
a) to use ShouldBeginEditing with return false, but you can't use PickerView as InputView in your text field.
b) to use ShouldChangeCharacters that will prevent the editing but will allow to use InputView with PickerView.
Objective C:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
return NO;
}
Swift :
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
return false
}
because you are working in MonoTouch you could use the following line of code:
myReadOnlyButton.ShouldBeginEditing = t =>
{
//event code
return false;
};
I personally use borderStyle = .none + userInteractionEnabled = false to make it look like a regular label.

Resources