I am trying to find which textfield is active for when the I move the view when the keyboard rises. I am trying to set a property in my viewcontroller from the subview of a
I first used Xilexio's solution but it was slow. I ended up using tags. Here is my code and set up as an example.
@property (nonatomic) NSInteger currentFormField;
typedef NS_ENUM(NSInteger, IOUFormField) {
IOUFormFieldName,
IOUFormFieldAmount,
IOUFormFieldDescription,
IOUFormFieldDate
};
...
self.nameField.tag = IOUFormFieldName;
self.amountField.tag = IOUFormFieldAmount;
self.descriptionField.tag = IOUFormFieldDescription;
self.dateField.tag = IOUFormFieldDate;
-(void)keyboardWillShow:(NSNotification *)notification {
// Move the scroll view to a position where the user can see the top and bottom form fields
// For example, if the user is on the description field, they should be able to see the date field and the amount field.
// The keyboard rect value comes as a NSValue * (a wrapped NSRect) with origin and size.
// The origin is using screen coordinates which is pixel based so don't use it.
// Use the size. Seems like it is density based.
CGFloat viewableScreenHeight = self.view.frame.size.height - keyboardFrameBeginRect.size.height;
// When the user is on a form field, get the current form field y position to where the scroll view should move to
CGFloat currentFormFieldYPosition = 0;
switch (self.currentFormField) {
case IOUFormFieldName:
{
currentFormFieldYPosition = self.nameField.frame.origin.y;
// If the scroll view is at the bottom and the user taps on the name field, move the scroll view to the top.
// This is so that users can see the give/get segments.
[self.scrollView setContentOffset:CGPointMake(0, 0) animated:YES];
break;
}
case IOUFormFieldAmount:
{
currentFormFieldYPosition = self.amountField.frame.origin.y;
break;
}
case IOUFormFieldDescription:
{
currentFormFieldYPosition = self.descriptionField.frame.origin.y;
break;
}
case IOUFormFieldDate:
{
currentFormFieldYPosition = self.dateField.frame.origin.y;
break;
}
default:
break;
}
// I want the current form field y position to be 100dp from the keyboard y position.
// 50dp for the current form field to be visible and another 50dp for the next form field so users can see it.
CGFloat leftoverTopHeight = viewableScreenHeight - 100;
// If the current form field y position is greater than the left over top height, that means that the current form field is hidden
// We make the calculations and then move the scroll view to the right position
if (currentFormFieldYPosition > leftoverTopHeight) {
CGFloat movedScreenPosition = currentFormFieldYPosition - leftoverTopHeight;
[self.scrollView setContentOffset:CGPointMake(0, movedScreenPosition) animated:YES];
}
}
#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
switch (textField.tag) {
case IOUFormFieldName:
self.currentFormField = IOUFormFieldName;
break;
case IOUFormFieldAmount:
self.currentFormField = IOUFormFieldAmount;
break;
case IOUFormFieldDescription:
self.currentFormField = IOUFormFieldDescription;
break;
case IOUFormFieldDate:
self.currentFormField = IOUFormFieldDate;
default:
break;
}
return true;
}
Let me know if you have any questions and I'll clarify. Note that the comments are for me. Also note that some code or omitted for brevity.
Based on Xilexio's answer but iterating over all the views to find the requested FirstResponder
View
-(UIView*)getFirstResponderInView:(UIView*)parentView{
UIView* requestedView = nil;
for (UIView *view in parentView.subviews) {
if (view.isFirstResponder) {
[view resignFirstResponder];
} else if (view.subviews.count > 0) {
requestedView = [self getFirstResponderInView:view];
}
if (requestedView != nil) {
return requestedView;
}
}
return nil;
}
Used like this :
UIView *view = [self getFirstResponderInView:self.view];
if(view != nil){
[self doSomethingCleverWithView:view];
}
In swift 3 use the function below function in your if else statements:
if (textField.isEditing)
[iOS] [swift3]
I did an extension for this.
public extension UIResponder {
private struct Static {
static weak var responder: UIResponder?
}
public static func currentFirst() -> UIResponder? {
Static.responder = nil
UIApplication.shared.sendAction(#selector(UIResponder._trap), to: nil, from: nil, for: nil)
return Static.responder
}
@objc private func _trap() {
Static.responder = self
}
}
Use:
if let activeTextField = UIResponder.currentFirst() as? UITextField {
// ...
}
Why dont you give all UITextfields individual Tags textfield.tag = 1
then you respond to the delegate DidBeginEditing. and check which textfield.tag is active?
You need to search for an object that has become a first responder. First responder object is the one using the keyboard (actually, it is he one having focus for user input). To check which text field uses the keyboard, iterate over your text fields (or just over all subviews) and use the isFirstResponder
method.
EDIT: As requested, a sample code, assuming all text fields are a subview of the view controller's view:
for (UIView *view in self.view.subviews) {
if (view.isFirstResponder) {
[self doSomethingCleverWithView:view];
}
}