Отримайте поточного першого відповіді без використання приватного API


340

Я подав свою програму трохи більше тижня тому і сьогодні отримав жахливе повідомлення про відхилення. Це говорить мені, що мою програму не можна прийняти, оскільки я використовую непублічний API; конкретно, це говорить,

Непублічний API, який включений у вашу заявку, є firstResponder.

Тепер образотворчий виклик API - це насправді рішення, яке я знайшов тут на SO:

UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
UIView   *firstResponder = [keyWindow performSelector:@selector(firstResponder)];

Як отримати поточний перший відповідь на екрані? Я шукаю спосіб, який не відхилить мою програму.


5
Замість того , щоб ітерація поглядів, ви можете використовувати це дійсно блискучі трохи магії: stackoverflow.com/a/14135456/746890
Кріс Нолет

Відповіді:


338

В одному зі своїх додатків я часто хочу, щоб перший відповідач пішов у відставку, якщо користувач натискає на задньому плані. Для цього я написав категорію на UIView, яку я викликаю у вікні UIW.

Далі ґрунтується на цьому і має повернути першого респондента.

@implementation UIView (FindFirstResponder)
- (id)findFirstResponder
{
    if (self.isFirstResponder) {
        return self;        
    }
    for (UIView *subView in self.subviews) {
        id responder = [subView findFirstResponder];
        if (responder) return responder;
    }
    return nil;
}
@end

iOS 7+

- (id)findFirstResponder
{
    if (self.isFirstResponder) {
        return self;
    }
    for (UIView *subView in self.view.subviews) {
        if ([subView isFirstResponder]) {
            return subView;
        }
    }
    return nil;
}

Швидкий:

extension UIView {
    var firstResponder: UIView? {
        guard !isFirstResponder else { return self }

        for subview in subviews {
            if let firstResponder = subview.firstResponder {
                return firstResponder
            }
        }

        return nil
    }
}

Приклад використання в Swift:

if let firstResponder = view.window?.firstResponder {
    // do something with `firstResponder`
}

278
Чому це краще рішення, ніж просто дзвінок [self.view endEditing:YES]?
Тім Салліван

69
@ Тим, я цього не зробив. Очевидно, це набагато простіший спосіб відставки першого відповідача. Однак це не допомагає з оригінальними запитаннями, які мали визначити першого респондента.
Томас Мюллер

17
Крім того, це краща відповідь, тому що ви, можливо, захочете зробити щось інше з першим відповідачем, ніж подати у відставку ...
Ерік Б

3
Слід зазначити, що це виявляє лише UIViews, а не інші UIResponders, які також можуть бути першим відповіддю (наприклад, UIViewController або UIApplication).
Патрік Пійнаппель

10
Чому різниця для iOS 7? Ви не хочете також повторюватися в такому випадку?
Peter DeWeese

531

Якщо ваша кінцева мета полягає у відставці першого відповідача, це має спрацювати: [self.view endEditing:YES]


122
Коли ви всі говорите, що це відповідь на "питання", можете поглянути на власне питання? Питання задає питання, як отримати поточного першого відповіді. Не як подати у відставку першого відповідача.
Justin Kredible

2
і де ми маємо назвати це самовідвідування endEditing?
user4951

8
Правда, що це не зовсім відповідь на питання, але очевидно, що це дуже корисна відповідь. Дякую!
NovaJoe

6
+1, навіть якщо це не відповідь на питання. Чому? Тому що багато хто приходить сюди із запитанням, на яке відповідає ця відповідь :) Принаймні, 267 (на даний момент) з них ...
Rok Jarc

1
Це не дає відповіді на запитання.
Сашо

186

Поширений спосіб маніпулювання першим респондентом - це використання нульових цільових дій. Це спосіб надсилання довільного повідомлення до ланцюжка відповідей (починаючи з першого відповіді) та продовження вниз по ланцюгу, поки хтось не відповість на повідомлення (не реалізував метод, відповідний селектору).

У випадку відхилення клавіатури це найефективніший спосіб роботи, незалежно від того, яке вікно або перегляд є першим відповіддю:

[[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];

Це має бути ефективнішим, ніж рівне [self.view.window endEditing:YES].

(Дякую BigZaphod, що нагадав мені про концепцію)


4
Це так круто. Можливо, найновіший трюк з какао-дотиком, який я ще бачив на SO Не допоміг мені кінця!
mluisbrown

це НАЙДАЛЕ найкраще рішення, дякую мільйон! це набагато краще, ніж рішення над цим, оскільки воно працює навіть із активного текстового поля - це частина перегляду аксесуарів клавіатури (у такому випадку це не є частиною нашої ієрархії зору)
Pizzaiola Gorgonzola

2
Це рішення є найкращим рішенням. Система вже знає, хто перший відповідь, її не потрібно шукати.
лівий шпиль

2
Я хочу дати цю відповідь більше, ніж один підсумок. Це виганяє геній.
Рейд Майн

1
devios1: Відповідь Якоба - це саме те, про що задається питання, але це хакерство в верхній частині системи респондентів, а не використання системи респондентів так, як це було розроблено. Це чистіше і втілює те, для чого більшість людей приходить до цього питання, і в однокласнику теж. (Звичайно, ви можете надіслати будь-яке повідомлення в стилі цільової дії, а не просто подати у відставкуFirstResponder).
невин

98

Ось категорія, яка дозволяє швидко знайти першого відповідача, зателефонувавши [UIResponder currentFirstResponder]. Просто додайте в проект наступні два файли:

UIResponder + FirstResponder.h

#import <Cocoa/Cocoa.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

Хитрість тут полягає в тому, що надсилання дії до нуля надсилає її першому відповідачу.

(Я спочатку опублікував цю відповідь тут: https://stackoverflow.com/a/14135456/322427 )


1
+1 Це найелегантніше рішення проблеми (і власне задане питання), яке я бачив ще. Багаторазові та ефективні! Підтвердьте цю відповідь!
devios1

3
Браво. Це може бути саме найкрасивіший і чистий хак, який я коли-небудь бачив для Objc ...
Авіель Гросс

Дуже хороший. Якщо слід по-справжньому добре працювати, то зможете запитати першого респондента, який (якщо хтось) у ланцюжку буде обробляти конкретний метод дій, якби він був надісланий. Ви можете використовувати це, щоб увімкнути або вимкнути елементи керування залежно від того, чи можна ними керувати. Я відповім на своє запитання з цього приводу і посилаюся на вашу відповідь.
Бенджон


Попередження: Це не працює, якщо ви починаєте додавати кілька вікон. Я, на жаль, поки не можу вказати на причину, що виходить за межі цього.
Хіт Межі

41

Ось розширення, впроваджене в Swift на основі найпрекраснішої відповіді Якоба Еггера:

import UIKit

extension UIResponder {
    // Swift 1.2 finally supports static vars!. If you use 1.1 see: 
    // http://stackoverflow.com/a/24924535/385979
    private weak static var _currentFirstResponder: UIResponder? = nil

    public class func currentFirstResponder() -> UIResponder? {
        UIResponder._currentFirstResponder = nil
        UIApplication.sharedApplication().sendAction("findFirstResponder:", to: nil, from: nil, forEvent: nil)
        return UIResponder._currentFirstResponder
    }

    internal func findFirstResponder(sender: AnyObject) {
        UIResponder._currentFirstResponder = self
    }
}

Швидкий 4

import UIKit    

extension UIResponder {
    private weak static var _currentFirstResponder: UIResponder? = nil

    public static var current: UIResponder? {
        UIResponder._currentFirstResponder = nil
        UIApplication.shared.sendAction(#selector(findFirstResponder(sender:)), to: nil, from: nil, for: nil)
        return UIResponder._currentFirstResponder
    }

    @objc internal func findFirstResponder(sender: AnyObject) {
        UIResponder._currentFirstResponder = self
    }
}

1
Змінена відповідь на для swift1.2, коли підтримується статичний var.
nacho4d

Привіт, коли я роздруковую результат цього на абсолютно новій програмі для одноразового перегляду у viewDidAppear (), я отримую нуль. Чи не повинен вигляд бути першим відгуком?
farhadf

@LinusGeffarth Чи не має сенсу викликати статичний метод currentзамість first?
Командир коду

Гадаю, редагував це. Я, здається, відмовився від важливої ​​частини при скороченні назви змінної.
LinusGeffarth

29

Це не дуже, але те, як я подаю у відставку першого респондента, коли я не знаю, що це за відповідь:

Створіть поле UITextField в IB або програмно. Зробіть це прихованим. Зв’яжіть його зі своїм кодом, якщо ви внесли його в IB.

Потім, коли ви хочете відхилити клавіатуру, ви перемикаєте респондент на невидиме текстове поле і негайно відміняєте його:

    [self.invisibleField becomeFirstResponder];
    [self.invisibleField resignFirstResponder];

61
Це одночасно жахливо і геніально. Приємно.
Алекс Уейн

4
Я вважаю це трохи небезпечним - Apple може одного дня вирішити, що зробити прихований контроль стати першим відповіддю - це не призначена поведінка, і "виправити" iOS більше не робити цього, і тоді ваш трюк може перестати працювати.
Томас Темпельман

2
Або ви можете призначити firstResponder поточному видимому UITextField, а потім викликати resignFirstResponder на цьому конкретному текстовому полі. Це знімає необхідність створити прихований вид. Все-таки +1.
Swifty McSwifterton

3
Я вважаю, що це лише жахливо ... він може змінити розкладку клавіатури (або вигляд вводу), перш ніж приховати її
Даніель,

19

Для версії Swift 3 і 4 у відповідь Невіна :

UIApplication.shared.sendAction(#selector(UIView.resignFirstResponder), to: nil, from: nil, for: nil)

10

Ось рішення, в якому повідомляється про правильний перший відповідь (про багато інших рішень не повідомлять про UIViewController як перший відповідь), не потребує циклічного перегляду над ієрархією перегляду та не використовує приватні API.

Він використовує метод Apple sendAction: to: from: forEvent: який вже знає, як отримати доступ до першого респондента.

Нам просто потрібно підправити його двома способами:

  • Розширити, UIResponderщоб він міг виконувати наш власний код на першому відповіді.
  • Підклас UIEventдля повернення першого відповіді.

Ось код:

@interface ABCFirstResponderEvent : UIEvent
@property (nonatomic, strong) UIResponder *firstResponder;
@end

@implementation ABCFirstResponderEvent
@end

@implementation UIResponder (ABCFirstResponder)
- (void)abc_findFirstResponder:(id)sender event:(ABCFirstResponderEvent *)event {
    event.firstResponder = self;
}
@end

@implementation ViewController

+ (UIResponder *)firstResponder {
    ABCFirstResponderEvent *event = [ABCFirstResponderEvent new];
    [[UIApplication sharedApplication] sendAction:@selector(abc_findFirstResponder:event:) to:nil from:nil forEvent:event];
    return event.firstResponder;
}

@end

7

Перший відповідь може бути будь-яким екземпляром класу UIResponder, тому є й інші класи, які можуть бути першим відповіддю, незважаючи на UIViews. Наприклад, UIViewControllerможе бути і перший відповідь.

У цьому суті ви знайдете рекурсивний спосіб отримати першого відповіді, провівши через ієрархію контролерів, починаючи з rootViewController вікон програми.

Ви можете отримати перший відповідь, зробивши це

- (void)foo
{
    // Get the first responder
    id firstResponder = [UIResponder firstResponder];

    // Do whatever you want
    [firstResponder resignFirstResponder];      
}

Однак якщо перший відповідь не є підкласом UIView або UIViewController, такий підхід буде невдалим.

Щоб вирішити цю проблему, ми можемо зробити інший підхід, створивши категорію UIResponderта виконавши магічне шипіння, щоб мати змогу створити масив усіх живих екземплярів цього класу. Тоді, щоб отримати першого відповіді, ми можемо просто проінтерувати і запитати кожен об'єкт, якщо -isFirstResponder.

Такий підхід можна знайти у цій іншій суті .

Сподіваюся, це допомагає.


7

Використання Swift та певного UIViewоб'єкта може допомогти:

func findFirstResponder(inView view: UIView) -> UIView? {
    for subView in view.subviews as! [UIView] {
        if subView.isFirstResponder() {
            return subView
        }

        if let recursiveSubView = self.findFirstResponder(inView: subView) {
            return recursiveSubView
        }
    }

    return nil
}

Просто помістіть його у свій UIViewControllerта використовуйте так:

let firstResponder = self.findFirstResponder(inView: self.view)

Зверніть увагу, що результат є необов’язковим значенням, тому він буде нульовим, якщо в поданих підглядах перегляду не було знайдено першогопопулярного.


5

Повторіть перегляд поглядів, які можуть стати першим відгуком, і використовуйте, - (BOOL)isFirstResponderщоб визначити, чи є вони в даний час.


4

Пітер Штейнбергер просто написав про приватному повідомленні UIWindowFirstResponderDidChangeNotification, яке ви можете спостерігати , якщо ви хочете стежити за зміною firstResponder.


Його відхиляють, оскільки використання приватного api, можливо, використання приватного повідомлення також може бути поганою ідеєю ...
Laszlo

4

Якщо вам просто потрібно вбити клавіатуру, коли користувач натискає на фонову область, чому б не додати розпізнавальник жестів і використовувати його для надсилання [[self view] endEditing:YES]повідомлення?

ви можете додати інструмент розпізнавання жестів Tap у файл xib або аркуша розкадри та підключити його до дії,

виглядає приблизно так, як потім закінчено

- (IBAction)displayGestureForTapRecognizer:(UITapGestureRecognizer *)recognizer{
     [[self view] endEditing:YES];
}

Це спрацювало для мене чудово. Я вибрав одне підключення до перегляду Xib, і я можу додати додаткові перегляди для цього, щоб посилатися на колекції Referencing Outlet Collection
James Perih

4

Якраз у цьому випадку - швидка версія дивовижного підходу Якоба Еггера:

import UIKit

private weak var currentFirstResponder: UIResponder?

extension UIResponder {

    static func firstResponder() -> UIResponder? {
        currentFirstResponder = nil
        UIApplication.sharedApplication().sendAction(#selector(self.findFirstResponder(_:)), to: nil, from: nil, forEvent: nil)
        return currentFirstResponder
    }

    func findFirstResponder(sender: AnyObject) {
        currentFirstResponder = self
    }

}

3

Це те, що я зробив, щоб знайти, що UITextField є першим Респондером, коли користувач натискає «Зберегти / Скасувати» в ModalViewController:

    NSArray *subviews = [self.tableView subviews];

for (id cell in subviews ) 
{
    if ([cell isKindOfClass:[UITableViewCell class]]) 
    {
        UITableViewCell *aCell = cell;
        NSArray *cellContentViews = [[aCell contentView] subviews];
        for (id textField in cellContentViews) 
        {
            if ([textField isKindOfClass:[UITextField class]]) 
            {
                UITextField *theTextField = textField;
                if ([theTextField isFirstResponder]) {
                    [theTextField resignFirstResponder];
                }

            }
        }

    }

}

2

Це те, що я маю в моїй категорії UIViewController. Корисно для багатьох речей, включаючи отримання першого відповіді. Блоки чудові!

- (UIView*) enumerateAllSubviewsOf: (UIView*) aView UsingBlock: (BOOL (^)( UIView* aView )) aBlock {

 for ( UIView* aSubView in aView.subviews ) {
  if( aBlock( aSubView )) {
   return aSubView;
  } else if( ! [ aSubView isKindOfClass: [ UIControl class ]] ){
   UIView* result = [ self enumerateAllSubviewsOf: aSubView UsingBlock: aBlock ];

   if( result != nil ) {
    return result;
   }
  }
 }    

 return nil;
}

- (UIView*) enumerateAllSubviewsUsingBlock: (BOOL (^)( UIView* aView )) aBlock {
 return [ self enumerateAllSubviewsOf: self.view UsingBlock: aBlock ];
}

- (UIView*) findFirstResponder {
 return [ self enumerateAllSubviewsUsingBlock:^BOOL(UIView *aView) {
  if( [ aView isFirstResponder ] ) {
   return YES;
  }

  return NO;
 }];
}


2

Ви можете вибрати таке UIViewрозширення, щоб отримати його (кредит Даніеля) :

extension UIView {
    var firstResponder: UIView? {
        guard !isFirstResponder else { return self }
        return subviews.first(where: {$0.firstResponder != nil })
    }
}

1

Ви також можете спробувати так:

- (void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event { 

    for (id textField in self.view.subviews) {

        if ([textField isKindOfClass:[UITextField class]] && [textField isFirstResponder]) {
            [textField resignFirstResponder];
        }
    }
} 

Я не пробував цього, але це здається гарним рішенням


1

Рішення від romeo https://stackoverflow.com/a/2799675/661022 - це класно, але я помітив, що для коду потрібен ще один цикл. Я працював з tableViewController. Я відредагував сценарій, а потім перевірив. Все працювало ідеально.

Я рекомендував спробувати це:

- (void)findFirstResponder
{
    NSArray *subviews = [self.tableView subviews];
    for (id subv in subviews )
    {
        for (id cell in [subv subviews] ) {
            if ([cell isKindOfClass:[UITableViewCell class]])
            {
                UITableViewCell *aCell = cell;
                NSArray *cellContentViews = [[aCell contentView] subviews];
                for (id textField in cellContentViews)
                {
                    if ([textField isKindOfClass:[UITextField class]])
                    {
                        UITextField *theTextField = textField;
                        if ([theTextField isFirstResponder]) {
                            NSLog(@"current textField: %@", theTextField);
                            NSLog(@"current textFields's superview: %@", [theTextField superview]);
                        }
                    }
                }
            }
        }
    }
}

Дякую! Ви маєте рацію, більшість представлених тут відповідей не є рішенням при роботі з uitableview. Ви можете дуже спростити свій код, навіть вийняти if if ([textField isKindOfClass:[UITextField class]]), дозволяючи використовувати uitextview, і міг би повернути перший відповідь.
Фрейд

1

Це хороший кандидат на рекурсію! Не потрібно додавати категорію до UIView.

Використання (з вашого контролера перегляду):

UIView *firstResponder = [self findFirstResponder:[self view]];

Код:

// This is a recursive function
- (UIView *)findFirstResponder:(UIView *)view {

    if ([view isFirstResponder]) return view; // Base case

    for (UIView *subView in [view subviews]) {
        if ([self findFirstResponder:subView]) return subView; // Recursion
    }
    return nil;
}

1

ви можете назвати привіт api так, яблуко ігнорувати:

UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
SEL sel = NSSelectorFromString(@"firstResponder");
UIView   *firstResponder = [keyWindow performSelector:sel];

1
але ... будь ласка, використовуй '
respondsToSelector

Я перевіряю 'respondsToSelector' зараз, але все одно отримую попередження, це може бути небезпечно. Чи можу я якось позбутися попередження?
ecth

1

Swift версія @ THOMAS-Muller відповідь «сек

extension UIView {

    func firstResponder() -> UIView? {
        if self.isFirstResponder() {
            return self
        }

        for subview in self.subviews {
            if let firstResponder = subview.firstResponder() {
                return firstResponder
            }
        }

        return nil
    }

}

1

У мене дещо інший підхід, ніж у більшості. Замість того, щоб повторювати колекцію переглядів, шукаючи isFirstResponderвстановлену, я теж надсилаю повідомлення nil, але я зберігаю приймач (якщо такий є), а потім повертаю це значення, щоб абонент отримував фактичний екземпляр (знову ж таки, якщо такий є) .

import UIKit

private var _foundFirstResponder: UIResponder? = nil

extension UIResponder{

    static var first:UIResponder?{

        // Sending an action to 'nil' implicitly sends it to the
        // first responder, where we simply capture it for return
        UIApplication.shared.sendAction(#selector(UIResponder.storeFirstResponder(_:)), to: nil, from: nil, for: nil)

        // The following 'defer' statement executes after the return
        // While I could use a weak ref and eliminate this, I prefer a
        // hard ref which I explicitly clear as it's better for race conditions
        defer {
            _foundFirstResponder = nil
        }

        return _foundFirstResponder
    }

    @objc func storeFirstResponder(_ sender: AnyObject) {
        _foundFirstResponder = self
    }
}

Тоді я можу піти у відставку першого відповідача, якщо такий є, зробивши це ...

return UIResponder.first?.resignFirstResponder()

Але я зараз теж можу це зробити ...

if let firstResponderTextField = UIResponder?.first as? UITextField {
    // bla
}

1

Я хотів би поділитися з вами моєю реалізацією для пошуку першого відповіді в будь-якій точці UIView. Я сподіваюся, що це допомагає і шкода моєї англійської. Дякую

+ (UIView *) findFirstResponder:(UIView *) _view {

    UIView *retorno;

    for (id subView in _view.subviews) {

        if ([subView isFirstResponder])
        return subView;

        if ([subView isKindOfClass:[UIView class]]) {
            UIView *v = subView;

            if ([v.subviews count] > 0) {
                retorno = [self findFirstResponder:v];
                if ([retorno isFirstResponder]) {
                    return retorno;
                }
            }
        }
    }

    return retorno;
}

0

Код нижче роботи.

- (id)ht_findFirstResponder
{
    //ignore hit test fail view
    if (self.userInteractionEnabled == NO || self.alpha <= 0.01 || self.hidden == YES) {
        return nil;
    }
    if ([self isKindOfClass:[UIControl class]] && [(UIControl *)self isEnabled] == NO) {
        return nil;
    }

    //ignore bound out screen
    if (CGRectIntersectsRect(self.frame, [UIApplication sharedApplication].keyWindow.bounds) == NO) {
        return nil;
    }

    if ([self isFirstResponder]) {
        return self;
    }

    for (UIView *subView in self.subviews) {
        id result = [subView ht_findFirstResponder];
        if (result) {
            return result;
        }
    }
    return nil;
}   

0

Оновлення: я помилявся. Ви дійсно можете використовувати UIApplication.shared.sendAction(_:to:from:for:)для виклику першого відповідача, продемонстрованого за цим посиланням: http://stackoverflow.com/a/14135456/746890 .


Більшість відповідей тут насправді не можуть знайти поточного першого відповіді, якщо він не знаходиться в ієрархії перегляду. Наприклад, AppDelegateабо UIViewControllerпідкласи.

Існує спосіб гарантувати вам його знайти, навіть якщо об'єктом першого відповіді не є UIView.

Спочатку давайте реалізувати зворотну версію її, використовуючи nextвластивість UIResponder:

extension UIResponder {
    var nextFirstResponder: UIResponder? {
        return isFirstResponder ? self : next?.nextFirstResponder
    }
}

За допомогою цього обчисленого властивості ми можемо знайти поточного першого відповіді знизу вгору, навіть якщо його немає UIView. Наприклад, від a viewдо theUIViewController хто ним керує, якщо контролер перегляду є першим відповіддю.

Однак нам все ще потрібна роздільна здатність зверху вниз, одинарна, varщоб отримати поточний перший відповідь.

Спочатку з ієрархією перегляду:

extension UIView {
    var previousFirstResponder: UIResponder? {
        return nextFirstResponder ?? subviews.compactMap { $0.previousFirstResponder }.first
    }
}

Це буде шукати першого відповіді заднім числом, і якщо він не зміг його знайти, він сказав би своїм підвідділам зробити те ж саме (тому що його підрозділ nextнеобов'язково сам). Завдяки цьому ми можемо знайти його з будь-якого погляду, в тому числі UIWindow.

І нарешті, ми можемо побудувати це:

extension UIResponder {
    static var first: UIResponder? {
        return UIApplication.shared.windows.compactMap({ $0.previousFirstResponder }).first
    }
}

Отже, коли ви хочете отримати першого відповіді, ви можете зателефонувати:

let firstResponder = UIResponder.first

0

Найпростіший спосіб знайти першого відповіді:

func sendAction(_ action: Selector, to target: Any?, from sender: Any?, for event: UIEvent?) -> Bool

Реалізація за замовчуванням посилає метод дії до заданого цільового об'єкта або, якщо не вказана ціль, до першого відповідача.

Наступний крок:

extension UIResponder
{
    private weak static var first: UIResponder? = nil

    @objc
    private func firstResponderWhereYouAre(sender: AnyObject)
    {
        UIResponder.first = self
    }

    static var actualFirst: UIResponder?
    {
        UIApplication.shared.sendAction(#selector(findFirstResponder(sender:)), to: nil, from: nil, for: nil)
        return UIResponder.first
    }
}

Використання: просто дістайтеся UIResponder.actualFirstдля власних цілей.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.