Enviei meu aplicativo há pouco mais de uma semana e recebi o temido e-mail de rejeição hoje. Ele diz que meu aplicativo não pode ser aceito porque estou usando uma API não pública; especificamente, diz,
A API não pública incluída no seu aplicativo é firstResponder.
Agora, a chamada da API ofensiva é na verdade uma solução que encontrei aqui no SO:
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
UIView *firstResponder = [keyWindow performSelector:@selector(firstResponder)];
Como obtenho a primeira resposta atual na tela? Estou procurando uma maneira de não rejeitar meu aplicativo.
objective-c
cocoa-touch
first-responder
Justin Kredible
fonte
fonte
Respostas:
Em um dos meus aplicativos, muitas vezes quero que o primeiro atendente se demita se o usuário tocar em segundo plano. Para esse fim, escrevi uma categoria no UIView, que chamo no UIWindow.
O seguinte é baseado nisso e deve retornar o primeiro respondedor.
iOS 7 ou superior
Rápido:
Exemplo de uso no Swift:
fonte
[self.view endEditing:YES]
?Se seu objetivo final é apenas renunciar ao primeiro respondedor, isso deve funcionar:
[self.view endEditing:YES]
fonte
Uma maneira comum de manipular o primeiro respondedor é usar ações direcionadas nulas. Essa é uma maneira de enviar uma mensagem arbitrária para a cadeia de respostas (começando com a primeira) e continuar na cadeia até que alguém responda à mensagem (implementou um método correspondente ao seletor).
No caso de descartar o teclado, esta é a maneira mais eficaz de funcionar, independentemente da janela ou exibição que responder primeiro:
Isso deve ser mais eficaz do que par
[self.view.window endEditing:YES]
.(Obrigado ao BigZaphod por me lembrar do conceito)
fonte
Aqui está uma categoria que permite encontrar rapidamente o primeiro respondedor ligando
[UIResponder currentFirstResponder]
. Basta adicionar os dois arquivos a seguir ao seu projeto:UIResponder + FirstResponder.h
UIResponder + FirstResponder.m
O truque aqui é que enviar uma ação para zero a envia para o primeiro respondedor.
(Eu originalmente publiquei esta resposta aqui: https://stackoverflow.com/a/14135456/322427 )
fonte
Aqui está uma extensão implementada no Swift com base na resposta mais excelente de Jakob Egger:
Swift 4
fonte
current
vez defirst
?Não é bonito, mas a maneira como eu renuncio o firstResponder quando não sei o que é esse respondedor:
Crie um UITextField, no IB ou programaticamente. Torná-lo oculto. Vincule-o ao seu código se você o criou no IB.
Então, quando você deseja descartar o teclado, alterne o respondedor para o campo de texto invisível e o renuncie imediatamente:
fonte
Para uma versão Swift 3 e 4 do da resposta nevyn :
fonte
Aqui está uma solução que reporta o socorrista correto (muitas outras soluções não relatam uma
UIViewController
como o primeiro respondedor, por exemplo), não requer loop na hierarquia de exibição e não usa APIs privadas.Ele aproveita o método da Apple sendAction: to: from: forEvent:, que já sabe como acessar o primeiro respondedor.
Só precisamos ajustá-lo de duas maneiras:
UIResponder
para que ele possa executar nosso próprio código na primeira resposta.UIEvent
para retornar o primeiro respondedor.Aqui está o código:
fonte
O primeiro respondedor pode ser qualquer instância da classe UIResponder; portanto, há outras classes que podem ser o primeiro a responder, apesar dos UIViews. Por exemplo
UIViewController
também pode ser o primeiro a responder.Em esta essência você vai encontrar uma maneira recursiva para obter a primeira resposta por looping através da hierarquia de controladores a partir do RootViewController das janelas do aplicativo.
Você pode recuperar o primeiro atendedor, fazendo
No entanto, se o primeiro respondedor não for uma subclasse de UIView ou UIViewController, essa abordagem falhará.
Para corrigir esse problema, podemos fazer uma abordagem diferente, criando uma categoria
UIResponder
e executando alguns swizzeling mágicos para poder construir uma matriz de todas as instâncias vivas dessa classe. Em seguida, para obter o primeiro respondedor, podemos iterar e perguntar a cada objeto se-isFirstResponder
.Esta abordagem pode ser encontrada implementada nesta outra essência .
Espero que ajude.
fonte
Usando o Swift e com um objeto específico,
UIView
isso pode ajudar:Basta colocá-lo no seu
UIViewController
e usá-lo assim:Observe que o resultado é um valor opcional, portanto será nulo caso nenhum firstResponser tenha sido encontrado nas subvisões de visualizações fornecidas.
fonte
Itere sobre as visualizações que poderiam ser o primeiro respondedor e use
- (BOOL)isFirstResponder
para determinar se elas estão atualmente.fonte
Peter Steinberger acabou de twittar sobre a notificação privada
UIWindowFirstResponderDidChangeNotification
, que você pode observar se quiser assistir à primeira alteração do Responsável.fonte
Se você só precisa matar o teclado quando o usuário toca em uma área de fundo, por que não adicionar um reconhecedor de gestos e usá-lo para enviar o
[[self view] endEditing:YES]
mensagem?você pode adicionar o reconhecedor de gestos ao toque no arquivo xib ou storyboard e conectá-lo a uma ação,
parece algo assim depois terminou
fonte
Apenas neste caso, aqui está a versão Swift da incrível abordagem de Jakob Egger:
fonte
Foi isso que fiz para descobrir qual UITextField é o firstResponder quando o usuário clica em Salvar / Cancelar em um ModalViewController:
fonte
É isso que tenho na minha categoria UIViewController. Útil para muitas coisas, incluindo a primeira resposta. Blocos são ótimos!
fonte
Com uma categoria ativada
UIResponder
, é possível solicitar legalmente aoUIApplication
objeto para informar quem é o primeiro respondedor.Veja isso:
Existe alguma maneira de perguntar à visualização do iOS qual de seus filhos tem o status de socorrista?
fonte
Você pode escolher a seguinte
UIView
extensão para obtê-lo (crédito por Daniel) :fonte
Você também pode tentar assim:
Eu não tentei, mas parece uma boa solução
fonte
A solução da romeo https://stackoverflow.com/a/2799675/661022 é legal, mas notei que o código precisa de mais um loop. Eu estava trabalhando com tableViewController. Eu editei o script e depois verifiquei. Tudo funcionou perfeitamente.
Eu recomendo tentar isso:
fonte
if ([textField isKindOfClass:[UITextField class]])
, permitindo o uso do uitextview, e pode retornar o responsável pela resposta.Este é um bom candidato para recursão! Não há necessidade de adicionar uma categoria ao UIView.
Uso (do seu controlador de exibição):
Código:
fonte
você pode chamar API privada assim, a apple ignora:
fonte
Versão rápida da resposta de @ thomas-müller
fonte
Eu tenho uma abordagem um pouco diferente da maioria aqui. Em vez de percorrer a coleção de visualizações procurando a que foi
isFirstResponder
configurada, eu também envio uma mensagem paranil
, mas armazeno o destinatário (se houver) e, em seguida, retorno esse valor para que o chamador obtenha a instância real (novamente, se houver) .Posso então renunciar ao primeiro atendedor, se houver, fazendo isso ...
Mas agora também posso fazer isso ...
fonte
Gostaria de compartilhar com você minha implementação para encontrar o primeiro respondedor em qualquer lugar do UIView. Espero que ajude e desculpe pelo meu inglês. obrigado
fonte
Código abaixo do trabalho.
fonte
Atualização: eu estava errado. Você pode usar
UIApplication.shared.sendAction(_:to:from:for:)
o primeiro respondedor demonstrado neste link: http://stackoverflow.com/a/14135456/746890 .A maioria das respostas aqui não consegue encontrar o primeiro respondente atual, se ele não estiver na hierarquia de visualizações. Por exemplo,
AppDelegate
ouUIViewController
subclasses.Existe uma maneira de garantir que você o encontre, mesmo que o primeiro objeto de resposta não seja a
UIView
.Primeiro vamos implementar uma versão invertida, usando a
next
propriedade deUIResponder
:Com essa propriedade computada, podemos encontrar o primeiro atendedor atual de baixo para cima, mesmo que não seja
UIView
. Por exemplo, de umview
para oUIViewController
quem está gerenciando, se o controlador de exibição for o primeiro a responder.No entanto, ainda precisamos de uma resolução de cima para baixo, uma única
var
para obter o primeiro atendedor atual.Primeiro com a hierarquia de visualizações:
Isso procurará o primeiro respondente de trás para frente e, se não o encontrasse, instruiria suas sub-visualizações a fazer a mesma coisa (porque as sub-visualizações
next
não são necessariamente elas mesmas ). Com isso, podemos encontrá-lo de qualquer ponto de vista, inclusiveUIWindow
.E, finalmente, podemos construir isso:
Portanto, quando você deseja recuperar a primeira resposta, pode ligar para:
fonte
Maneira mais simples de encontrar o socorrista:
Próxima Etapa:
Uso: Basta obter
UIResponder.actualFirst
para seus próprios propósitos.fonte