有没有办法询问 iOS 视图的哪个子视图具有第一响应者状态? [重复]

问题描述 投票:0回答:4

在 Mac OS X 中,您可以这样找到第一响应者:

[[self window] firstResponder]

iOS 有什么方法可以实现吗? 或者您是否需要枚举子控件并向每个子控件发送一条

isFirstResponder
消息?

ios cocoa-touch uiresponder responder-chain
4个回答
254
投票

我真的很喜欢VJK 的解决方案,但正如 MattDiPasquale 所说,它似乎比必要的更复杂。所以我写了这个更简单的版本:

目标-C

UIResponder+FirstResponder.h:

#import <UIKit/UIKit.h>

@interface UIResponder (FirstResponder)
    +(id)currentFirstResponder;
@end

UIResponder+FirstResponder.m:

#import "UIResponder+FirstResponder.h"

static __weak id currentFirstResponder;

@implementation UIResponder (FirstResponder)

+(id)currentFirstResponder {
    currentFirstResponder = nil;
    [[UIApplication sharedApplication] sendAction:@selector(findFirstResponder:) to:nil from:nil forEvent:nil];
    return currentFirstResponder;
}

-(void)findFirstResponder:(id)sender {
   currentFirstResponder = self;
}

@end

斯威夫特4

import UIKit

extension UIResponder {

    private static weak var _currentFirstResponder: UIResponder?

    static var currentFirstResponder: UIResponder? {
        _currentFirstResponder = nil
        UIApplication.shared.sendAction(#selector(UIResponder.findFirstResponder(_:)), to: nil, from: nil, for: nil)

        return _currentFirstResponder
    }

    @objc func findFirstResponder(_ sender: Any) {
        UIResponder._currentFirstResponder = self
    }
}

我还将它设为一个类方法,因为这似乎更有意义。您现在可以像这样找到第一响应者:

[UIResponder currentFirstResponder]


注意:这并不总是有效。例如,在初始化 UIImagePickerController 后,UIResponder.currentFirstResponder 返回 nil。如果您需要此使用https://stackoverflow.com/a/50472291/3393964

textField.becomeFirstResponder()
print(UIResponder.currentFirstResponder) // UITextField
_ = UIImagePickerController()
print(UIResponder.currentFirstResponder) // nil


27
投票

我在

UIResponder
上写了一个类别来寻找第一响应者

@interface UIResponder (firstResponder)
- (id) currentFirstResponder;
@end

#import <objc/runtime.h>
#import "UIResponder+firstResponder.h"

static char const * const aKey = "first";

@implementation UIResponder (firstResponder)

- (id) currentFirstResponder {
    [[UIApplication sharedApplication] sendAction:@selector(findFirstResponder:) to:nil from:self forEvent:nil];
    id obj = objc_getAssociatedObject (self, aKey);
    objc_setAssociatedObject (self, aKey, nil, OBJC_ASSOCIATION_ASSIGN);
    return obj;
}

- (void) setCurrentFirstResponder:(id) aResponder {
    objc_setAssociatedObject (self, aKey, aResponder, OBJC_ASSOCIATION_ASSIGN);
}

- (void) findFirstResponder:(id) sender {
    [sender setCurrentFirstResponder:self];
}

@end

然后在任何派生自

UIResponder
的类中,您可以通过调用

获得第一响应者
UIResponder* aFirstResponder = [self currentFirstResponder];

但是记得先导入UIResponder类别接口文件!

这使用记录的 API,因此应该不会出现应用商店拒绝问题。


13
投票

如果您需要第一响应者,以便可以要求其放弃其状态,这里有一种让任何人辞职的方法。 UIView 有一个方法将遍历所有 UIView 子视图并要求任何第一响应者退出。

[[self view] endEditing:YES];

这里是 Apple 的 UIView 文档的链接 “此方法查看当前视图及其子视图层次结构,以查找当前作为第一响应者的文本字段。如果找到一个,它会要求该文本字段辞去第一响应者的角色。如果force参数设置为YES,则文本字段甚至从未被要求;它被迫辞职。”


11
投票

您需要迭代所有子控件并测试

isFirstResponder
属性。当遇到
TRUE
时,跳出循环。

UIView *firstResponder;
for (UIView *view in self.view.subviews) //: caused error
{
    if (view.isFirstResponder)
    {
        firstResponder = view;
        break;
    }
}

更好的解决方案

参见雅各布的回答

© www.soinside.com 2019 - 2024. All rights reserved.