题 试图找到哪个文本字段是活动的ios


我试图找到当键盘上升时我移动视图时哪个文本字段处于活动状态。我正在尝试从scrollview的子视图中设置我的viewcontroller中的属性。

这是我用来在scrollview中显示视图的代码

-(void)displayView:(UIViewController *)viewController{

[[viewFrame subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)]; 
[viewFrame scrollRectToVisible:CGRectMake(0, 0, 1, 1)
                        animated:NO];

[viewFrame addSubview: viewController.view];

_currentViewController = viewController;
}

- 编辑 -

我改变了对这个问题的思考方式。对不起,我发布时问题含糊不清。当时我很精疲力竭,这在我脑海里是有道理的。

一个不同但相似的问题:UITextArea和UITextView的公共子类是否会给我firstResponder的起源?或者,在找到原点之前,我还需要检查第一个响应者的类吗?


23
2017-08-29 08:33


起源


您应该尝试找到哪个UI元素是当前的第一个响应者。 - holex
我刚刚更新了我的代码,因为我错过了一部分。 - RMDan
第一响应者是活跃的 UITextView 元件, 你的问题很模糊。 一个可能的解决方案是你可能会创建一个协议,你应该委托你的类,或类似的东西,最终的解决方案取决于你的代码是如何构建的以及你喜欢用活动做什么 UITextField。 - holex
清理了我的问题。对不起,当我发布它并且没想到我在问什么时,我很累。 - RMDan


答案:


您需要搜索已成为第一响应者的对象。第一响应者对象是使用键盘的人(实际上,他是一个具有用户输入焦点的人)。要检查哪个文本字段使用键盘,请迭代文本字段(或仅覆盖所有子视图)并使用 isFirstResponder 方法。

编辑: 根据要求,示例代码,假设所有文本字段都是视图控制器视图的子视图:

for (UIView *view in self.view.subviews) {
    if (view.isFirstResponder) {
        [self doSomethingCleverWithView:view];
    }
}

34
2017-08-29 08:48



你能展示一些示例代码吗?我不熟悉Obj-C中的迭代。 - RMDan
请注意,这只会迭代 即时 (一级深)视图控制器的子级。您需要使用递归方法来深入挖掘。 - devios1


我做了一个扩展。

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
    }
}

使用:

if let activeTextField = UIResponder.currentFirst() as? UITextField {
    // ...
}

20
2017-11-01 00:29



完善!谢谢!!! - Steven.B
是的,这应该是最好的答案 - Paul T.
很棒的答案。谢谢 - Afshin
整齐!起初我就像“嗯?”所以万一其他人对这是如何工作感到困惑。这是来自的文档 sendAction:默认实现将action方法分派给给定的目标对象,如果没有指定目标,则分配给第一个响应者 - Keith Norman


假设您的文本字段完全相同(即所有货币或文本)并且不需要任何特殊格式,我建议如下:

首先,有一个可选的textField变量。例如:

var currentTextField: UITextField?

然后添加以下内容:

func textFieldDidBeginEditing(textField: UITextField) {

        currentTextField = textField

}

现在,您可以使用“活动”文本字段执行任何操作,除非需要某些特定的格式化操作,否则无需跟踪任何标记。


2
2017-12-11 14:26





为什么不给所有UITextfields单独的标签textfield.tag = 1

然后你回复代表DidBeginEditing。并检查哪个textfield.tag是活动的?


1
2017-08-29 09:41



我不确定标签实际上是如何工作的,所以目前我没有使用它们。我不认为这会有所帮助,因为子视图当前将第一个响应者保存为指针,但问题是将该指针作为包含子视图的scrollview的父级。 - RMDan


我第一次使用Xilexio的解决方案,但速度很慢。我最终使用标签。这是我的代码并设置为示例。

@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;
}

如果您有任何问题,请告诉我,我会澄清。请注意,评论适合我。还要注意一些代码或为简洁而省略。


1
2017-10-23 17:56





在swift 3中,在if else语句中使用以下函数:

    if (textField.isEditing) 

[iOS] [swift3]


1
2018-06-29 17:47





基于 Xilexio的回答 但迭代所有视图以查找请求的 FirstResponder 视图

-(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;
}

像这样使用:

UIView *view = [self getFirstResponderInView:self.view];
if(view != nil){
    [self doSomethingCleverWithView:view];
}

0
2017-10-01 01:20