Zamknij klawiaturę, dotykając tła UITableView


105

Mam UITableViewze UITextFields jak komórki. Chciałbym odrzucić klawiaturę po UITableViewdotknięciu tła . Próbuję to zrobić, tworząc UIButtonrozmiar UITableViewi umieszczając go za UITableView. Jedynym problemem jest toUIButton przechwytuje wszystkie dotknięcia, nawet gdy dotyk jest w UITableView. Co ja robię źle?

Dzięki!


Powiązane pytania i odpowiedzi: Q1 , Q2 , Q3 .
— Yantao Xie,

To jest najlepsza odpowiedź stackoverflow.com/a/12851794/1418457
— onmyway133

Odpowiedzi:


203

Można to łatwo zrobić, tworząc UITapGestureRecognizer obiekt (domyślnie spowoduje to wykrycie „gestu” po jednym dotknięciu, więc dalsze dostosowywanie nie jest wymagane), określając cel / akcję, gdy gest jest uruchamiany, a następnie dołączając obiekt rozpoznawania gestów do widoku tabeli.

Np. Być może w Twojej viewDidLoadmetodzie:

UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard)];
[self.tableView addGestureRecognizer:gestureRecognizer];

A hideKeyboardmetoda może wyglądać następująco:

- (void) hideKeyboard {
    [textField1 resignFirstResponder];
    [textField2 resignFirstResponder];
    ...
    ...
}

Zwróć uwagę, że gest nie jest wykonywany podczas dotykania wnętrza UITextFieldobiektu. Jest uruchamiany w UITableViewtle, widoku stopki, widoku nagłówka i UILabelswewnątrz komórek itp.


4
Kiedy to wypróbowałem, okazało się, że uniemożliwiło to wybranie komórek przez tabelę :(. Niesamowite rozwiązanie w przeciwnym razie
— Brian

109
gestureRecognizer.cancelsTouchesInView = NO;
— Poniższe

3
I nie zapomnij zwolnić gestRecognizer po dołączeniu go do tableView.
— Paul Lynch,

39
W przypadku hideKeyboardmetody, zamiast komunikować się bezpośrednio z polami tekstowymi, możesz to zrobić [self.view endEditing:NO];. Z dokumentów Apple: „ Ta metoda sprawdza bieżący widok i jego hierarchię podglądy dla pola tekstowego, które jest obecnie pierwszą osobą odpowiadającą. Jeśli znajdzie, prosi to pole tekstowe o rezygnację jako pierwsza osoba odpowiadająca. Jeśli parametr siły jest ustawiony na TAK, pole tekstowe nigdy nie jest
— pytane

1
w ten sposób moja metoda „didSelectRowAtIndexPath” nie jest wywoływana. jakieś rozwiązanie na to?
— uniruddh

127

Rozwiązanie UITapGestureRecognizer działa z zaznaczaniem komórek tabeli, jeśli ustawisz:

gestureRecognizer.cancelsTouchesInView = NO;

1
Pozwala to na dotknięcie komórki, ale gest jest również rozpoznawany, być może powinniśmy wdrożyć te metody delegatashouldReceiveTouch
— onmyway133

61

Oto najlepszy sposób, aby to zrobić. Po prostu zrób to

[self.view endEditing:YES];

lub

[[self.tableView superView] endEditing:YES];

gdzie mam umieścić ten kod? przepraszam jestem początkującym. I podaj szybki kod.
— John

54

Możesz to również zrobić w Storyboard: wprowadź opis obrazu tutaj


1
Cokolwiek wybiorę: Dismiss on drag, Dismiss Interaktywnie, kiedy dotykam komórki tabeli, jest ona zaznaczona. Używam Xcode 8, swift 3. Proszę o pomoc
— Jan

22

Podobnie UITableViewjak podklasa UIScrollView, implementacja jednej metody delegata poniżej zapewnia niezwykle łatwe i szybkie rozwiązanie. Nie ma potrzeby nawet się angażować, resignFirstResponderponieważ przeglądanie hierarchii przeprowadza introspekcję i znajduje obecnego respondenta i prosi go o rezygnację ze statusu respondenta.

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    [self.view endEditing:YES];
}

I pamiętaj, aby dodać UIScrollViewDelegatedo pliku nagłówkowego.


2
Można to zrobić za pomocą tej jednej linijki, jak wskazał @Joe Masilotti, jeśli celujesz w system iOS7 i nowszy: self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
— atulkhatri

Co się stanie, jeśli dotkniesz pola tekstowego u dołu ekranu, które ma przewijać się w górę, aby wyświetlić klawiaturę? - Twoja klawiatura zostanie ukryta.
— Islam Q.

Swift 4 - self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissMode.onDrag
— RobLabs

13

Po pierwsze, posłuchaj scrollViewWillBeginDraggingw swoim UIViewController, dodającUIScrollViewDelegate :

W pliku .h:

@interface MyViewController : UIViewController <UIScrollViewDelegate> 

W pliku .m:

- (void)scrollViewWillBeginDragging:(UIScrollView *)activeScrollView {

    [self dismissKeyboard];

}

Następnie posłuchaj innych interakcji:

- (void)setupKeyboardDismissTaps {

    UISwipeGestureRecognizer *swipeUpGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
    swipeUpGestureRecognizer.cancelsTouchesInView = NO;
    swipeUpGestureRecognizer.direction = UISwipeGestureRecognizerDirectionUp;
    [self.tableView addGestureRecognizer:swipeUpGestureRecognizer];

    UISwipeGestureRecognizer *swipeDownGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
    swipeDownGestureRecognizer.cancelsTouchesInView = NO;
    swipeDownGestureRecognizer.direction = UISwipeGestureRecognizerDirectionDown;
    [self.tableView addGestureRecognizer:swipeDownGestureRecognizer];

    UISwipeGestureRecognizer *swipeLeftGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
    swipeLeftGestureRecognizer.cancelsTouchesInView = NO;
    swipeLeftGestureRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
    [self.tableView addGestureRecognizer:swipeLeftGestureRecognizer];

    UISwipeGestureRecognizer *swipeRightGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
    swipeRightGestureRecognizer.cancelsTouchesInView = NO;
    swipeRightGestureRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
    [self.tableView addGestureRecognizer:swipeRightGestureRecognizer];


    UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
    tapGestureRecognizer.cancelsTouchesInView = NO;
    [self.tableView addGestureRecognizer:tapGestureRecognizer];

}

Następnie zastosuj dismissKeyboard:

- (void)dismissKeyboard {

    NSLog(@"dismissKeyboard");

    [yourTextFieldPointer resignFirstResponder];

}

A jeśli, tak jak ja, chcesz odrzucić klawiaturę dla UITextField wewnątrz niestandardowej komórki tabeli:

- (void)dismissKeyboard {

    NSLog(@"dismissKeyboard");

    CustomCellClass *customCell = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
    [customCell.textFieldInCell resignFirstResponder]; 

}

Mam nadzieję, że pomoże to każdemu w wyszukiwaniu!



8

Oto szybka wersja dla przyjemności z kodowania:

Dodaje rozpoznawanie gestów stuknięcia, a następnie odrzuca klawiaturę. Nie jest wymagane gniazdko dla TextField!

override func viewDidLoad() {
    super.viewDidLoad()
    view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "handleTap:"))
}

func handleTap(sender: UITapGestureRecognizer) {
    if sender.state == .Ended {
        view.endEditing(true)
    }
    sender.cancelsTouchesInView = false
}

1
Działa to nawet z niestandardowym tableViewCell! Spędziłem tyle czasu, próbując to rozgryźć. Dziękuję bardzo! Jesteś moim bohaterem. youtu.be/EqWRaAF6_WY
— peacetype

8

Dostępna jest wersja Swift 3 bez blokowania dotknięć komórek.

W viewDidLoad()metodzie:

let dismissKeyboardGesture = UITapGestureRecognizer(target: self, action: #selector(hideKeyboard))
dismissKeyboardGesture.cancelsTouchesInView = false
tableView.addGestureRecognizer(dismissKeyboardGesture)

I hideKeyboardwygląda tak:

func hideKeyboard() {
    view.endEditing(true)
}

7

Zrobiłem to tak:

Utwórz metodę w swoim TableViewController, aby dezaktywować pierwszy responder (który byłby wtedy Twoim TextBox)

- (BOOL)findAndResignFirstResonder:(UIView *)stView {
    if (stView.isFirstResponder) {
        [stView resignFirstResponder];
        return YES;     
    }

    for (UIView *subView in stView.subviews) {
        if ([self findAndResignFirstResonder:subView]) {
            return YES;
        }
    }
    return NO;
}

W tableView:didSelectRowAtIndexPath:wywołaniu poprzednia metoda:

- (void)tableView:(UITableView *)tableView
                             didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    ...
    [self findAndResignFirstResonder: self.view];
    ...
}

robisz to źle, o co prosisz. nie umieszczasz przycisku w widoku, mówisz widokowi, aby usunął klawiaturę, tak jak mówi ta odpowiedź

2
Działa to pięknie, jeśli dotkniesz komórki widoku tabeli (i poza jakąkolwiek UITextField w tej komórce widoku tabeli). Jeśli jednak dotknę tła widoku tabeli (który często jest łatwiejszym celem - prawo yay Fitts!), Nie mam szczęścia. To prawda, jest to oczekiwane, ponieważ wykonujemy tę operację w tableView: didSelectRowAtIndexPath :. Jeśli można to w jakiś sposób dostosować, aby działało z stukaniem w dowolnym innym miejscu w widoku tabeli (które w przeciwnym razie nie wymagałoby fokusu na klawiaturze), myślę, że mamy tutaj zwycięzcę!
— Joe D'Andrea

Mam ten sam problem co jdandrea. To didSelectRowAtIndexPathsię nie uruchamia, jeśli dotkniesz samego TableView.
— zekel

jeśli didSelectRowAtIndexPath nie jest wystarczające, zrób to samo w przypadku dotknięćBegan!
— Amogh Talpallikar,

5

Miałem UITableViewControlleri implementacja touchesBegan:withEvent:nie zadziałała.

Oto, co zadziałało:

Szybki:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    view.endEditing(true)
}

Cel C:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [self.view endEditing:YES];
}

Dobry pomysł, podoba mi się.
— HotFudge w niedzielę

4
@interface DismissableUITableView : UITableView {
}
@end

@implementation DismissableUITableView

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
 [self.superview endEditing:YES];
 [super touchesBegan:touches withEvent:event];
}

@end

Następnie upewnij się, że w pliku Nib ustawiłeś typ swojego UITableView na DismissableUITableView ..... może mógłbym wymyślić lepszą nazwę dla tej klasy, ale o co chodzi.


4

Jeśli kierujesz reklamy na iOS7, możesz użyć jednej z następujących opcji:

tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;

tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;

Pierwsza z nich będzie animować klawiaturę poza ekranem, gdy widok tabeli jest przewijany, a druga ukryje klawiaturę, podobnie jak standardowa aplikacja Wiadomości.

Zauważ, że są one z UIScrollView, które UITableViewdziedziczy z.


miły. Udało mi się to przełamać, przesuwając palcem w dół z góry w górę ekranu, aż klawiatura zaczęła się przesuwać w dół, a następnie przesuwając z powrotem w górę, aż klawiatura przesunęła się trochę w górę, a następnie puszczając. widok przewijania nie powraca do góry tak, jak powinien.
— Sam

3

Spróbuj tego:

viewDidLoad(){

    let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))

    tableView.addGestureRecognizer(tap)

}
//Calls this function when the tap is recognized.
@objc func dismissKeyboard() {

    //Causes the view (or one of its embedded text fields) to resign the first responder status.
    view.endEditing(true)

}

2

UITableView jest podklasą UIScrollView.

Sposób, w jaki to zrobiłem, polegał na nasłuchiwaniu zdarzenia przewijania przez użytkownika, a następnie rezygnacji z FirstResponder. Oto metoda UIScrollViewDelegate do zaimplementowania w kodzie;

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView

Przy podejściu do tego rodzaju problemów stwierdziłem, że najlepszym sposobem jest zbadanie protokołów delegatów dla każdego obiektu i klas nadrzędnych (w tym przypadku UITableViewDelegate, UIScrollViewDelegate. Liczba zdarzeń wywoływanych przez obiekty NS jest dość duża i wyczerpująca. łatwiejsze jest także implementowanie protokołu, a następnie tworzenie podklas.


2

Miałem ten sam problem i oto moje rozwiązanie, u mnie działa idealnie:

W zaimplementowanym kontrolerze widoku lub widoku <UITextFieldDelegate>

(W moim przypadku mam zwyczaj UITableViewCell nazwę TextFieldCell),

Zadeklaruj UITapGestureRecognizerjako właściwość:

@interface TextFieldCell : UITableViewCell <UITextFieldDelegate>
{
    UITextField *theTextField;
    UITapGestureRecognizer *gestureRecognizer;
}
@property (nonatomic,retain) UITextField *theTextField;
@property (nonatomic,retain) UITapGestureRecognizer *gestureRecognizer; 

I zainicjuj go w swoim widoku / kontrolerze:

self.gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(closeKeyboard:)];

W - (void)textFieldDidBeginEditing:(UITextField *)textFieldmetodzie użyj, superViewaby przejść do swojego tableView i wywołaj addGestureRecognizer:

[self.superview.superview addGestureRecognizer:gestureRecognizer];

Po - (void)textFieldDidEndEditing:(UITextField *)textFieldprostu usuń aparat rozpoznawania gestów:

[self.superview.superview removeGestureRecognizer:gestureRecognizer];

Mam nadzieję, że to pomoże.


Zrobiło to dla mnie. Dzięki hac.jack
— gilsaints88

2

Chciałem, aby moja komórka otwierała klawiaturę po wybraniu dowolnej części komórki i zamykała ją, jeśli klikniesz w dowolnym miejscu poza komórką. Aby otworzyć klawiaturę:

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];
    if (selected)
    {
        [self.textField becomeFirstResponder];
    }
}

(UWAGA: podklasowałem komórkę, ale możesz to łatwo osiągnąć w tableView:didSelectRowAtIndexPath:metodzie delegataUITableView )

Oznaczało to, że w przypadku najlepszych rozwiązań, jeśli dwukrotnie klikniesz komórkę, klawiatura będzie się trząść, ponieważ najpierw mechanizm rozpoznawania gestów próbował zamknąć klawiaturę, a po drugie komórka została ponownie wybrana i spróbowała otworzyć klawiaturę.

Rozwiązaniem jest sprawdzenie, czy kliknięcie nastąpiło w aktualnie wybranej komórce:

- (void)viewDidLoad
{
    [super viewDidLoad];
    //gesture recognizer to close the keyboard when user taps away
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                          action:@selector(dismissKeyboard:)];
    tap.cancelsTouchesInView = NO;
    [self.tableView addGestureRecognizer:tap];
}

-(void)dismissKeyboard:(UIGestureRecognizer*)tapGestureRecognizer
{
    if (!CGRectContainsPoint([self.tableView cellForRowAtIndexPath:[self.tableView indexPathForSelectedRow]].frame, [tapGestureRecognizer locationInView:self.tableView]))
    {
        [self.view endEditing:YES];
    }
}

2

Znalazłem rozwiązanie, które działa świetnie.

Jest potrzebne do użycia UIGestureRecognizerDelegate i metody - GestRecognizer: shouldReceiveTouch: .

Dodaj aparat rozpoznawania gestów do TableView w następujący sposób:

UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard)];
tapGestureRecognizer.cancelsTouchesInView = NO;
tapGestureRecognizer.delegate = self;
[self.suggestedTableView addGestureRecognizer:tapGestureRecognizer];
[tapGestureRecognizer release];

Następnie zaimplementuj metodę delegata shouldReceiveTouch , aby odrzucić dotknięcia wykonywane w klasie UITableViewCell. Metoda hideKeyboard zostanie wywołana tylko wtedy, gdy dotknięcie zostało wykonane poza klasą UITableViewCell.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    if([touch.view isKindOfClass:[UITableViewCell class]]) {
        return NO;
    }
    // UITableViewCellContentView => UITableViewCell
    if([touch.view.superview isKindOfClass:[UITableViewCell class]]) {
        return NO;
    }
    // UITableViewCellContentView => UITableViewCellScrollView => UITableViewCell
    if([touch.view.superview.superview isKindOfClass:[UITableViewCell class]]) {
        return NO;
    }
    return YES; // handle the touch
}

- (void) hideKeyboard{
    [textField resignFirstResponder];
}

2

UITableViewma przydatną backgroundViewwłaściwość, dzięki której osiągnąłem to zachowanie bez mieszania się przy wyborze komórek, jak pokazano poniżej w Swift:

let tableBackTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(hideKeyboard))
tableView.backgroundView = UIView()
tableView.backgroundView?.addGestureRecognizer(tableBackTapRecognizer)


1

Po prostu użycie UITapGestureRecognizer i cancelsTouchesInView = NOoznacza, że dotknięcie komórek i UITextViews również wyzwalają ukrywanie. To jest złe, jeśli masz wiele UITextViews i stukasz w następny. Klawiatura zacznie się ukrywać, a następnie następny textView stanie się pierwszym Responderem, a klawiatura znów stanie się widoczna. Aby tego uniknąć, sprawdź lokalizację dotknięcia i ukryj klawiaturę tylko wtedy, gdy dotknięcie nie znajduje się w komórce:

// init
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapTableView:)];
tapRecognizer.cancelsTouchesInView = NO;
[self.tableView addGestureRecognizer:tapRecognizer];


// Hide on tap
- (void)didTapTableView:(UITapGestureRecognizer *)tap
{
    CGPoint point = [tap locationInView:tap.view];
    [self.view endEditing:!CGRectContainsPoint([self.tableView rectForRowAtIndexPath:[self.tableView indexPathForRowAtPoint:point]], point)];
}

Aby scrollViewWillBeginDragging:funkcja tableView została wyzwolona, scrollEnabledmusi mieć wartośćYES

// Hide on scroll
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    [self.view endEditing:YES];
}

Idealne dla mnie. Dodano pole tekstowe do komórki widoku tabeli; jeśli dotknę poza klawiaturą, zwolnij
— Nicola

0

Dlaczego chcesz utworzyć tabelę pełną pól tekstowych? Powinieneś używać widoku szczegółowego dla każdego wiersza zawierającego pola tekstowe. Kiedy wysyłasz swój szczegółowy widok, upewnij się, że wywołujesz „[myTextField staje sięFirstResponder]”, aby użytkownik mógł rozpocząć edycję jednym kliknięciem od listy tabel.


Aplikacja Kontakty Apple robi dokładnie to. Nie powiedziałbym, że jest pełen pól tekstowych jako takich, ale wykorzystuje je z dobrym skutkiem.
— Joe D'Andrea

2
Edycja tekstu bezpośrednio w widoku tabeli jest znacznie szybsza i bardziej intuicyjna niż przekazywanie widoków szczegółów dla każdego pola tekstowego, które użytkownik chce edytować ... wystarczy poprosić o najbliższy formularz HTML lub pola tekstowe w panelach preferencji iPhone'a lub w aplikacji Kontakty lub etc etc etc ... szkoda, że ​​Apple nie uczynił tego standardowego typu komórki, ale w sieci jest wiele informacji na temat osiągnięcia tego.
— glenc

0

Jeśli chcesz podklasować (ugh!) Swój widok tabeli, może zadziałać coś takiego :

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

   BOOL backgroundTouched = YES;

   for (UITouch *touch in touches) {
      CGPoint location = [touch locationInView:self];
      for (UITableViewCell *cell in self.visibleCells) {
         if (CGRectContainsPoint(cell.frame, location)) {
            backgroundTouched = NO;
            break;
         }
      }
   }

   if (backgroundTouched) {
      for (UITableViewCell *cell in self.visibleCells) {
         // This presumes the first subview is the text field you want to resign.
         [[cell.contentView.subviews objectAtIndex:0] resignFirstResponder];
      }
   }

   [super touchesBegan:touches withEvent:event];
}

0

Jeśli chcesz odrzucić klawiaturę podczas naciskania klawisza Return, możesz po prostu dodać następujący kod w textField powinien zwrócić metodę, tj .:

- (BOOL)textFieldShouldReturn:(UITextField *)atextField
{
   [textField resignFirstresponder];
}

Niektóre pola tekstowe mogą mieć widok selektora lub inny jako widok podrzędny, więc w takim przypadku powyższa metoda nie działa, więc w takim przypadku musimy skorzystać z klasy UITapGestureRecognizer, tj. Dodać następujący fragment kodu do metody viewDidLoad, tj .:

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                          action:@selector(dismissKeyboard)];

    [self.view addGestureRecognizer:tap];

Teraz po prostu dodaj respondera rezygnującego do metody selektora, tj .:

-(void)dismissKeyboard 
{
    [textField resignFirstResponder];
}

Mam nadzieję, że to pomoże, dzięki :)


0

Wiele ciekawych odpowiedzi. Chciałbym skompilować różne podejścia do rozwiązania, które moim zdaniem najlepiej pasuje do scenariusza UITableView (jest to ten, którego zwykle używam): Zwykle chcemy ukryć klawiaturę w dwóch scenariuszach: po dotknięciu poza elementami interfejsu tekstowego, lub podczas przewijania w dół / w górę UITableView. Pierwszy scenariusz możemy łatwo dodać za pomocą TapGestureRecognizer, a drugi za pomocą metody UIScrollViewDelegate scrollViewWillBeginDragging:. Pierwsza sprawa, sposób na ukrycie klawiatury:

   /**
     *  Shortcut for resigning all responders and pull-back the keyboard
     */
    -(void)hideKeyboard
    {
        //this convenience method on UITableView sends a nested message to all subviews, and they resign responders if they have hold of the keyboard
        [self.tableView endEditing:YES];

    }

Ta metoda rezygnuje z dowolnego interfejsu użytkownika textField z podglądów podrzędnych w hierarchii widoku UITableView, więc jest bardziej praktyczna niż rezygnacja z każdego pojedynczego elementu niezależnie.

Następnie zajmiemy się zwolnieniem za pomocą zewnętrznego gestu Tap, za pomocą:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self setupKeyboardDismissGestures];

}

- (void)setupKeyboardDismissGestures
{

//    Example for a swipe gesture recognizer. it was not set-up since we use scrollViewDelegate for dissmin-on-swiping, but it could be useful to keep in mind for views that do not inherit from UIScrollView
//    UISwipeGestureRecognizer *swipeUpGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard)];
//    swipeUpGestureRecognizer.cancelsTouchesInView = NO;
//    swipeUpGestureRecognizer.direction = UISwipeGestureRecognizerDirectionUp;
//    [self.tableView addGestureRecognizer:swipeUpGestureRecognizer];

    UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard)];
    //this prevents the gestureRecognizer to override other Taps, such as Cell Selection
    tapGestureRecognizer.cancelsTouchesInView = NO;
    [self.tableView addGestureRecognizer:tapGestureRecognizer];

}

Ustawienie opcji tapGestureRecognizer.cancelsTouchesInView na NO ma na celu uniknięcie zastąpienia przez gestRecognizer normalnych wewnętrznych działań UITableView (na przykład nie kolidować z zaznaczaniem komórki).

Wreszcie, aby obsłużyć ukrywanie klawiatury przy przewijaniu w górę / w dół UITableView, musimy zaimplementować protokół UIScrollViewDelegate scrollViewWillBeginDragging: method, jako:

plik .h

@interface MyViewController : UIViewController <UIScrollViewDelegate>

plik .m

#pragma mark - UIScrollViewDelegate

-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    [self hideKeyboard];
}

Mam nadzieję, że to pomoże! =)


0

Oto, jak w końcu stworzyłem prace. Połączyłem sugestie i kody z różnych odpowiedzi. Funkcje: odrzucanie klawiatury, przesuwanie pól tekstowych nad klawiaturą podczas edycji i ustawianie typu powrotu klawiatury „Dalej” i „Gotowe”. ZAMIEŃ „...” na więcej pól

static const CGFloat ANIMATION_DURATION = 0.4;
static const CGFloat LITTLE_SPACE = 5;
CGFloat animatedDistance;
CGSize keyboardSize;

@interface ViewController () <UITextFieldDelegate>
 @property (weak, nonatomic) IBOutlet UITextField *firstNameTXT;
  .....// some other text fields
 @property (weak, nonatomic) IBOutlet UITextField *emailTXT;
@end

@implementation ViewController
- (void)viewDidLoad{
.....
// add tap gesture to help in dismissing keyboard
UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc]
                                       initWithTarget:self
                                       action:@selector(tapScreen:)];// outside textfields

[self.view addGestureRecognizer:tapGesture];

// set text fields return key type to Next, last text field to Done
[self.firstNameTXT setReturnKeyType:UIReturnKeyNext];
.....
[self.emailTXT setReturnKeyType:UIReturnKeyDone];

// set text fields tags
[self.firstNameTXT setTag:0];
....// more text fields
[self.emailTXT setTag:5];

// add keyboard notification
[[NSNotificationCenter defaultCenter] addObserver:self     selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
}
[[NSNotificationCenter defaultCenter] addObserver:self      selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
}

// dismiss keyboard when tap outside text fields
- (IBAction)tapScreen:(UITapGestureRecognizer *)sender {
  if([self.firstNameTXT isFirstResponder])[self.firstNameTXT resignFirstResponder];
  ...
  if([self.emailTXT isFirstResponder])[self.emailTXT  resignFirstResponder];

  }
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
   if(textField.returnKeyType==UIReturnKeyNext) {
     // find the text field with next tag
     UIView *next = [[textField superview] viewWithTag:textField.tag+1];
     [next becomeFirstResponder];
   } else if (textField.returnKeyType==UIReturnKeyDone || textField.returnKeyType==UIReturnKeyDefault) {
    [textField resignFirstResponder];
 }
return YES;
}

// Moving current text field above keyboard
-(BOOL) textFieldShouldBeginEditing:(UITextField*)textField{
   CGRect viewFrame = self.view.frame;
   CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField];
   CGRect viewRect = [self.view.window convertRect:self.view.bounds fromView:self.view];
   CGFloat textFieldBottomLine = textFieldRect.origin.y + textFieldRect.size.height + LITTLE_SPACE;//

   CGFloat keyboardHeight = keyboardSize.height;

   BOOL isTextFieldHidden = textFieldBottomLine > (viewRect.size.height - keyboardHeight)? TRUE :FALSE;
  if (isTextFieldHidden) {
    animatedDistance = textFieldBottomLine - (viewRect.size.height - keyboardHeight) ;
    viewFrame.origin.y -= animatedDistance;
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:ANIMATION_DURATION];
    [self.view setFrame:viewFrame];
    [UIView commitAnimations];
  }
  return YES;
}

-(void) restoreViewFrameOrigionYToZero{
  CGRect viewFrame = self.view.frame;
  if (viewFrame.origin.y != 0) {
    viewFrame.origin.y = 0;
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:ANIMATION_DURATION];
    [self.view setFrame:viewFrame];
    [UIView commitAnimations];
  }
}

-(void)keyboardDidShow:(NSNotification*)aNotification{
   NSDictionary* info = [aNotification userInfo];
   keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
 }

-(void)keyboardDidHide:(NSNotification*)aNotification{
   [self restoreViewFrameOrigionYToZero];// keyboard is dismissed, restore frame view to its  zero origin
}
@end

0

Odpowiedź @ mixca jest bardzo przydatna, ale co, jeśli mam coś innego niż UITextField. Myślę, że najlepszym sposobem na to jest przeszukanie wszystkich podwidoków widoku głównego z funkcją rekurencyjną, sprawdź poniższy przykład

- (BOOL)findAndResignFirstResponder {
if (self.isFirstResponder) {
    [self resignFirstResponder];
    return YES;
}

    for (UIView *subView in self.subviews) {
        if ([subView findAndResignFirstResponder]) {
            return YES;
        }
    }
    return NO;
}

a także możesz umieścić tę metodę w swojej klasie narzędziowej i użyć gestu dotknięcia, takiego jak odpowiedź @ mixca.


0

Swift 4 / 4,2 / 5

Możesz także zamknąć klawiaturę po dotknięciu komórki - zanim zrobisz cokolwiek innego.

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    view.endEditing(true)
    // Do something here
    }

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.