Get the current first responder without using a private API

前端 未结 28 1828
夕颜
夕颜 2020-11-22 05:03

I submitted my app a little over a week ago and got the dreaded rejection email today. It tells me that my app cannot be accepted because I\'m using a non-public API; specif

相关标签:
28条回答
  • 2020-11-22 05:54

    Here's a category that allows you to quickly find the first responder by calling [UIResponder currentFirstResponder]. Just add the following two files to your project:

    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
    

    The trick here is that sending an action to nil sends it to the first responder.

    (I originally published this answer here: https://stackoverflow.com/a/14135456/322427)

    0 讨论(0)
  • 2020-11-22 05:55

    In one of my applications I often want the first responder to resign if the user taps on the background. For this purpose I wrote a category on UIView, which I call on the UIWindow.

    The following is based on that and should return the first responder.

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

    Swift:

    extension UIView {
        var firstResponder: UIView? {
            guard !isFirstResponder else { return self }
    
            for subview in subviews {
                if let firstResponder = subview.firstResponder {
                    return firstResponder
                }
            }
    
            return nil
        }
    }
    

    Usage example in Swift:

    if let firstResponder = view.window?.firstResponder {
        // do something with `firstResponder`
    }
    
    0 讨论(0)
  • 2020-11-22 05:55

    The first responder can be any instance of the class UIResponder, so there are other classes that might be the first responder despite the UIViews. For example UIViewController might also be the first responder.

    In this gist you will find a recursive way to get the first responder by looping through the hierarchy of controllers starting from the rootViewController of the application's windows.

    You can retrieve then the first responder by doing

    - (void)foo
    {
        // Get the first responder
        id firstResponder = [UIResponder firstResponder];
    
        // Do whatever you want
        [firstResponder resignFirstResponder];      
    }
    

    However, if the first responder is not a subclass of UIView or UIViewController, this approach will fail.

    To fix this problem we can do a different approach by creating a category on UIResponder and perform some magic swizzeling to be able to build an array of all living instances of this class. Then, to get the first responder we can simple iterate and ask each object if -isFirstResponder.

    This approach can be found implemented in this other gist.

    Hope it helps.

    0 讨论(0)
  • 2020-11-22 05:55

    I would like to shared with you my implementation for find first responder in anywhere of UIView. I hope it helps and sorry for my english. Thanks

    + (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 讨论(0)
  • 2020-11-22 05:56

    Swift version of @thomas-müller's response

    extension UIView {
    
        func firstResponder() -> UIView? {
            if self.isFirstResponder() {
                return self
            }
    
            for subview in self.subviews {
                if let firstResponder = subview.firstResponder() {
                    return firstResponder
                }
            }
    
            return nil
        }
    
    }
    
    0 讨论(0)
  • 2020-11-22 05:58

    With a category on UIResponder, it is possible to legally ask the UIApplication object to tell you who the first responder is.

    See this:

    Is there any way of asking an iOS view which of its children has first responder status?

    0 讨论(0)
提交回复
热议问题