Przesłałem aplikację nieco ponad tydzień temu i otrzymałem dziś przerażającą wiadomość e-mail o odrzuceniu. Mówi mi, że mojej aplikacji nie można zaakceptować, ponieważ korzystam z niepublicznego interfejsu API; konkretnie, mówi:
Niepubliczny interfejs API zawarty w aplikacji to firstResponder.
Teraz obrażające wywołanie API jest rozwiązaniem, które znalazłem tutaj na SO:
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
UIView *firstResponder = [keyWindow performSelector:@selector(firstResponder)];
Jak wyświetlić bieżącego pierwszego odpowiadającego na ekranie? Szukam sposobu, który nie spowoduje odrzucenia mojej aplikacji.
objective-c
cocoa-touch
first-responder
Justin Kredible
źródło
źródło
Odpowiedzi:
W jednej z moich aplikacji często chcę, aby pierwszy odpowiadający zrezygnował, jeśli użytkownik dotknie tła. W tym celu napisałem kategorię na UIView, którą nazywam na UIWindow.
Poniższe informacje są oparte na tym i powinny zwrócić pierwszy obiekt odpowiadający.
iOS 7+
Szybki:
Przykład użycia w Swift:
źródło
[self.view endEditing:YES]
?Jeśli Twoim ostatecznym celem jest po prostu zrezygnowanie z pierwszego odpowiadającego, powinno to działać:
[self.view endEditing:YES]
źródło
Częstym sposobem manipulowania pierwszym responderem jest użycie zerowych działań ukierunkowanych. Jest to sposób wysłania dowolnej wiadomości do łańcucha odpowiadającego (zaczynając od pierwszego odpowiadającego) i kontynuowania w dół łańcucha, dopóki ktoś nie odpowie na wiadomość (zaimplementował metodę pasującą do selektora).
W przypadku wyłączenia klawiatury jest to najskuteczniejszy sposób, który zadziała bez względu na to, które okno lub widok odpowiada jako pierwszy:
To powinno być bardziej skuteczne niż nawet
[self.view.window endEditing:YES]
.(Podziękowania dla BigZaphod za przypomnienie mi o koncepcji)
źródło
Oto kategoria, która pozwala szybko znaleźć pierwszego odpowiadającego, dzwoniąc
[UIResponder currentFirstResponder]
. Wystarczy dodać następujące dwa pliki do swojego projektu:UIResponder + FirstResponder.h
UIResponder + FirstResponder.m
Sztuczka polega na tym, że wysłanie akcji do zera powoduje wysłanie jej do pierwszego obiektu odpowiadającego.
(Oryginalnie opublikowałem tę odpowiedź tutaj: https://stackoverflow.com/a/14135456/322427 )
źródło
Oto rozszerzenie zaimplementowane w Swift w oparciu o najdoskonalszą odpowiedź Jakoba Eggera:
Szybki 4
źródło
current
zamiastfirst
?To nie jest ładne, ale sposób, w jaki rezygnuję z pierwszego odpowiedzi, gdy nie wiem, co to jest odpowiadający:
Utwórz pole UITextField w IB lub programowo. Ukryj to. Połącz go ze swoim kodem, jeśli wykonałeś go w IB.
Następnie, gdy chcesz zwolnić klawiaturę, przełączasz odpowiadającego na niewidoczne pole tekstowe i natychmiast go rezygnujesz:
źródło
W przypadku wersji Swift 3 i 4 odpowiedzi Nevyna :
źródło
Oto rozwiązanie, które zgłasza poprawnego pierwszego odpowiadającego (wiele innych rozwiązań nie zgłasza na przykład
UIViewController
jako pierwszego odpowiadającego), nie wymaga zapętlania hierarchii widoku i nie korzysta z prywatnych interfejsów API.Wykorzystuje metodę Apple sendAction: to: from: forEvent:, która już wie, jak uzyskać dostęp do pierwszego respondera.
Musimy go tylko ulepszyć na 2 sposoby:
UIResponder
aby mógł wykonać nasz własny kod na pierwszym responderze.UIEvent
w celu zwrócenia pierwszego obiektu odpowiadającego.Oto kod:
źródło
Pierwszym responderem może być dowolna instancja klasy UIResponder, więc istnieją inne klasy, które mogą być pierwszą odpowiedzią pomimo UIViews. Na przykład
UIViewController
może być również pierwszy odpowiadający.W tej liście znajdziesz rekursywny sposób na uzyskanie pierwszego obiektu odpowiadającego, przechodząc przez hierarchię kontrolerów, zaczynając od rootViewController w oknach aplikacji.
Możesz wtedy odzyskać pierwszego odpowiadającego, robiąc
Jednak jeśli pierwszy obiekt odpowiadający nie jest podklasą UIView lub UIViewController, to podejście zakończy się niepowodzeniem.
Aby rozwiązać ten problem, możemy zastosować inne podejście, tworząc kategorię
UIResponder
i wykonać magiczne zamiatanie, aby móc zbudować tablicę wszystkich żywych instancji tej klasy. Następnie, aby uzyskać pierwszą odpowiedź, możemy po prostu iterować i pytać każdy obiekt, czy-isFirstResponder
.To podejście można znaleźć zaimplementowane w tej innej istocie .
Mam nadzieję, że to pomoże.
źródło
Używanie Swift i konkretnego
UIView
obiektu może pomóc:Po prostu włóż go do swojego
UIViewController
i użyj go w następujący sposób:Zwróć uwagę, że wynik jest wartością opcjonalną, więc będzie zero, na wypadek, gdyby nie znaleziono firstResponser w podviewach podanych widoków.
źródło
Powtarzaj poglądy, które mogą być pierwszą odpowiedzią, i użyj ich,
- (BOOL)isFirstResponder
aby ustalić, czy obecnie są.źródło
Peter Steinberger właśnie napisał tweeta o prywatnym powiadomieniu
UIWindowFirstResponderDidChangeNotification
, które możesz obserwować, jeśli chcesz zobaczyć pierwszą zmianę odpowiedzi.źródło
Jeśli musisz po prostu zabić klawiaturę, gdy użytkownik stuknie w tło, dlaczego nie dodać rozpoznawania gestów i użyć go do wysłania
[[self view] endEditing:YES]
wiadomości?możesz dodać narzędzie do rozpoznawania gestów Tap w pliku xib lub pliku scenorysu i połączyć je z akcją,
wygląda mniej więcej tak, a potem skończył
źródło
Wystarczy, że tutaj jest Swift wersja niesamowitego podejścia Jakoba Eggera:
źródło
Oto, co zrobiłem, aby dowiedzieć się, który obiekt UITextField jest pierwszym odpowiedzią, gdy użytkownik kliknie Zapisz / Anuluj w ModalViewController:
źródło
To właśnie mam w mojej kategorii UIViewController. Przydatny do wielu rzeczy, w tym do uzyskania pierwszej odpowiedzi. Bloki są świetne!
źródło
Przy włączonej kategorii
UIResponder
można legalnie poprosićUIApplication
obiekt o informację, kto jest pierwszym responderem.Zobacz:
Czy jest jakiś sposób, by zapytać widok iOS, które z jego dzieci ma status pierwszej odpowiedzi?
źródło
Możesz wybrać następujące
UIView
rozszerzenie, aby je zdobyć (autor: Daniel) :źródło
Możesz spróbować również w ten sposób:
Nie próbowałem tego, ale wydaje się to dobrym rozwiązaniem
źródło
Rozwiązanie z Romea https://stackoverflow.com/a/2799675/661022 jest fajne, ale zauważyłem, że kod wymaga jeszcze jednej pętli. Pracowałem z tableViewController. Zredagowałem skrypt, a potem sprawdziłem. Wszystko działało idealnie.
Poleciłem spróbować tego:
źródło
if ([textField isKindOfClass:[UITextField class]])
, pozwalając na użycie uitextview, i możesz zwrócić pierwszego korespondenta.To dobry kandydat do rekurencji! Nie musisz dodawać kategorii do UIView.
Użycie (z kontrolera widoku):
Kod:
źródło
możesz wywołać prywatny api w ten sposób, Apple ignoruje:
źródło
Swift wersja @ Thomas-Muller odpowiedzi „s
źródło
Mam nieco inne podejście niż większość tutaj. Zamiast iterować kolekcję widoków szukających tego, który
isFirstResponder
ustawił, ja również wysyłam wiadomośćnil
, ale przechowuję odbiornik (jeśli istnieje), a następnie zwracam tę wartość, aby osoba dzwoniąca otrzymała rzeczywistą instancję (ponownie, jeśli w ogóle) .Mogę zrezygnować z pierwszego odpowiadającego, jeśli taki istnieje, wykonując to ...
Ale teraz mogę to zrobić ...
źródło
Chciałbym udostępnić Ci moją implementację, aby znaleźć pierwszą odpowiedź w dowolnym miejscu UIView. Mam nadzieję, że to pomaga i przepraszam za mój angielski. Dzięki
źródło
Kod poniżej pracy.
źródło
Aktualizacja: Myliłem się. Rzeczywiście możesz użyć,
UIApplication.shared.sendAction(_:to:from:for:)
aby zadzwonić do pierwszego respondenta pokazanego w tym linku: http://stackoverflow.com/a/14135456/746890 .Większość odpowiedzi tutaj nie może naprawdę znaleźć bieżącego pierwszego odpowiadającego, jeśli nie znajduje się on w hierarchii widoków. Na przykład
AppDelegate
lubUIViewController
podklasy.Istnieje sposób, aby zagwarantować, że go znajdziesz, nawet jeśli pierwszym obiektem odpowiadającym nie jest
UIView
.Najpierw zaimplementuj jego odwróconą wersję, używając
next
właściwościUIResponder
:Dzięki tej obliczonej właściwości możemy znaleźć bieżącego pierwszego odpowiadającego od dołu do góry, nawet jeśli nie jest
UIView
. Na przykład od aview
do tego,UIViewController
kto nim zarządza, jeśli kontroler widoku jest pierwszym odpowiadającym.Jednak nadal potrzebujemy odgórnej rozdzielczości, pojedynczej,
var
aby uzyskać obecną pierwszą odpowiedź.Najpierw z hierarchią widoków:
Spowoduje to wyszukanie pierwszego odpowiadającego wstecz i gdyby nie mógł go znaleźć, powiedziałby swoim podwykonawcom, aby zrobili to samo (ponieważ jego widok podrzędny
next
niekoniecznie jest sam). Dzięki temu możemy go znaleźć z dowolnego widoku, w tymUIWindow
.I wreszcie możemy zbudować to:
Więc jeśli chcesz odzyskać pierwszego respondenta, możesz zadzwonić:
źródło
Najprostszy sposób na znalezienie pierwszego odpowiadającego:
Następny krok:
Zastosowanie: Po prostu weź
UIResponder.actualFirst
własne cele.źródło