Есть ли способ спросить у iOS, кто из ее детей имеет статус первого респондента?

В Mac OS X вы можете найти первого респондента следующим образом:

[[self window] firstResponder]

Есть ли способ сделать это в iOS? Или вам нужно перечислить дочерние элементы управления и отправить isFirstResponderсообщение каждому?

4 ответа

Решение

Вам нужно будет перебрать все дочерние элементы управления и проверить isFirstResponder имущество. Когда вы сталкиваетесь TRUEвырваться из петли.

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

ЛУЧШЕЕ РЕШЕНИЕ

Смотрите ответ Якоба.

Мне действительно нравится решение VJK, но, как предполагает MattDiPasquale, оно кажется более сложным, чем необходимо. Итак, я написал эту более простую версию:

Objective-C

#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

Swift 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]


Я написал категорию на 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, поэтому не должно быть проблем с отклонением в магазине приложений.

Если вам нужен первый респондент только для того, чтобы вы могли попросить его уйти в отставку, вот способ заставить любого уйти в отставку. В UIView есть метод, который будет перебирать все подпредставления UIViews и запрашивать всех, кто первым ответит, подать в отставку.

[[self view] endEditing:YES];

Вот ссылка на Apple UIView Docs: "Этот метод просматривает текущее представление и его иерархию подпредставления для текстового поля, которое в настоящее время является первым респондентом. Если он находит его, он просит это текстовое поле подать в отставку как первый респондент. Если сила для параметра установлено значение YES, текстовое поле даже не запрашивается; оно вынуждено уйти в отставку."

Другие вопросы по тегам