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!

Hua-Ying
źródło
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.

mixja
źródło
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;
Azbuky
źródło
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];
Saad
źródło
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

Ben
źródło
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.

Rajive Jain
źródło
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!

bbeckford
źródło
12
tableView.keyboardDismissMode = .onDrag
Dom Bryan
źródło
szukał tego: D
Tobias
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
}
Biodave
źródło
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)
}
Ivan Smetanin
źródło
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];
    ...
}
sha
źródło
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];
}
MontiRabbit
źródło
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.

bandejapaisa
źródło
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.

Joe Masilotti
źródło
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)

}
Michael Colonna
źródło
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.

pschang
źródło
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.

hac.jack
źródło
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];
    }
}
Sam
źródło
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];
}
mlabraca
źródło
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)
Şafak Gezer
źródło
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];
}
Shawn Throop
źródło
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.

Mugunth
źródło
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];
}
Joe D'Andrea
źródło
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 :)

Eshwar Chaitanya
źródło
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! =)

Robertibiris
źródło
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
Kamel
źródło
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.

mert
źródło
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
    }
N. Der
źródło
0

tableView.keyboardDismissMode = .onDrag // .interactive

K. Mitra
źródło