Ignora la tastiera toccando lo sfondo di UITableView


105

Ho una UITableViewcon UITextFields come cellule. Vorrei chiudere la tastiera quando UITableViewviene toccato lo sfondo di . Sto provando a farlo creando un UIButtonle dimensioni di UITableViewe posizionandolo dietro UITableView. L'unico problema è che UIButtonsta catturando tutti i tocchi anche quando il tocco è su UITableView. Che cosa sto facendo di sbagliato?

Grazie!


Domande e risposte relative: Q1 , Q2 , Q3 .
Yantao Xie

Questa è la migliore risposta stackoverflow.com/a/12851794/1418457
onmyway133

Risposte:


203

Questo può essere fatto facilmente creando un oggetto UITapGestureRecognizer (per impostazione predefinita questo rileverà un "gesto" su un singolo tocco, quindi non è necessaria alcuna ulteriore personalizzazione), specificando un obiettivo / azione per quando il gesto viene attivato e quindi allegando l'oggetto di riconoscimento del gesto alla visualizzazione tabella.

Ad esempio, forse nel tuo viewDidLoadmetodo:

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

E il hideKeyboardmetodo potrebbe essere simile a questo:

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

Nota che il gesto non viene attivato quando si tocca l'interno di un UITextFieldoggetto. Viene attivato anche se sullo UITableViewsfondo, nella vista a piè di pagina, nella vista dell'intestazione e nelle UILabelscelle interne ecc.


4
Quando ho provato questo, ho scoperto che impediva alla tabella di selezionare le celle :(. Ottima soluzione altrimenti
Brian

109
Come soluzione sotto sottolinea che puoi rendere questo lavoro molto migliore impostando:gestureRecognizer.cancelsTouchesInView = NO;
Zebs

3
E non dimenticare di rilasciare il gestureRecognizer una volta che è collegato a tableView.
Paul Lynch

39
Per il hideKeyboardmetodo, invece di comunicare direttamente con i campi di testo puoi farlo [self.view endEditing:NO];. Da Apple docs: " Questo metodo esamina la vista corrente e la sua sottoview gerarchia per il campo di testo che è attualmente il primo risponditore. Se ne trova uno, chiede a quel campo di testo di dimettersi come primo risponditore. Se il parametro force è impostato su SÌ, il campo di testo non viene nemmeno chiesto; è costretto a dimettersi. "
Gobot

1
utilizzando in questo modo il mio metodo "didSelectRowAtIndexPath" non viene chiamato. qualche soluzione per questo ??
uniruddh

127

La soluzione UITapGestureRecognizer funziona con la selezione delle celle della tabella se si imposta:

gestureRecognizer.cancelsTouchesInView = NO;

1
Ciò consente di toccare la cella, ma viene riconosciuto anche il gesto, forse dovremmo implementare questo metodo delegatoshouldReceiveTouch
onmyway133

61

Ecco il modo migliore per farlo. Fallo e basta

[self.view endEditing:YES];

o

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

dove devo mettere questo codice? scusa sono principiante. E si prega di fornire il codice swift.
John

54

Puoi anche farlo da Storyboard: inserisci qui la descrizione dell'immagine


1
Qualunque cosa scelga: Ignora trascinando, Ignora interattivamente, quando tocco la cella della tabella, viene selezionata. Sto usando Xcode 8, swift 3. per favore aiuto
John

22

Essendo UITableViewuna sottoclasse di UIScrollView, l'implementazione di un metodo delegato di seguito fornisce una soluzione estremamente semplice e rapida. Non c'è nemmeno bisogno di coinvolgere resignFirstResponderpoiché visualizza la gerarchia introspettiva e trova il risponditore corrente e gli chiede di dimettersi dal suo stato di risponditore.

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

E ricorda di aggiungere UIScrollViewDelegateal file di intestazione.


2
Questo può essere fatto tramite questa linea, come sottolineato da @Joe Masilotti se stai prendendo di mira iOS7 e versioni successive: self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
atulkhatri

Cosa succede se tocchi un campo di testo nella parte inferiore dello schermo che dovrebbe scorrere verso l'alto per mostrare la tastiera? - La tua tastiera sarà nascosta.
Islam Q.

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

13

In primo luogo, ascolta scrollViewWillBeginDraggingnel tuo UIViewControlleraggiungendo UIScrollViewDelegate:

Nel file .h:

@interface MyViewController : UIViewController <UIScrollViewDelegate> 

Nel file .m:

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

    [self dismissKeyboard];

}

Quindi ascolta altre interazioni:

- (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];

}

Quindi implementare dismissKeyboard:

- (void)dismissKeyboard {

    NSLog(@"dismissKeyboard");

    [yourTextFieldPointer resignFirstResponder];

}

E se, come me, volessi chiudere la tastiera per un UITextField all'interno di una cella di tabella personalizzata:

- (void)dismissKeyboard {

    NSLog(@"dismissKeyboard");

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

}

Spero che questo aiuti chiunque cerchi !!



8

Ecco la versione rapida per il tuo piacere di codifica:

Aggiunge un riconoscimento dei gesti di tocco quindi chiude la tastiera. Non è richiesta alcuna presa per 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
Funziona anche con un tableViewCell personalizzato! Ho passato così tanto tempo a cercare di capirlo. Grazie mille! Tu sei il mio eroe. youtu.be/EqWRaAF6_WY
peacetype

8

Esiste la versione Swift 3 senza bloccare i tocchi sulle celle.

Nel viewDidLoad()metodo:

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

E hideKeyboardassomiglia a questo:

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

7

L'ho fatto così:

Crea un metodo nel tuo TableViewController per disattivare il primo risponditore (che sarebbe il tuo TextBox a quel punto)

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

In tableView:didSelectRowAtIndexPath:chiamata il metodo precedente:

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

lo stai facendo male nel modo in cui lo chiedi. non metti un pulsante sulla vista, dici alla vista di rimuovere la tastiera come dice questa risposta

2
Funziona magnificamente se tocchi all'interno di una cella della vista tabella (e all'esterno di qualsiasi UITextField all'interno di quella cella della vista tabella). Tuttavia, se tocco lo sfondo della visualizzazione della tabella (che spesso è un obiettivo più facile da raggiungere - evviva la legge di Fitts!), Nessuna fortuna. È vero, è previsto, poiché stiamo eseguendo questa operazione all'interno di tableView: didSelectRowAtIndexPath :. Se questo può essere regolato in qualche modo per funzionare toccando in qualsiasi altro punto della vista tabella (altrimenti non vorrebbe il focus della tastiera), penso che qui abbiamo un vincitore!
Joe D'Andrea

Ho lo stesso problema di jdandrea. Ciò didSelectRowAtIndexPathnon si attiva se tocchi il TableView stesso.
zekel

se didSelectRowAtIndexPath non è sufficiente, fai lo stesso anche in touchesBegan!
Amogh Talpallikar

5

Avevo un UITableViewControllere l'implementazione touchesBegan:withEvent:non ha funzionato per me.

Ecco cosa ha funzionato:

Swift:

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

Objective-C:

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

Buona idea, mi piace.
HotFudgeDomenica

4
@interface DismissableUITableView : UITableView {
}
@end

@implementation DismissableUITableView

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

@end

Quindi assicurati di impostare il tipo di UITableView nel file Nib su DismissableUITableView ..... forse avrei potuto pensare a un nome migliore per questa classe, ma hai capito.


4

Se scegli come target iOS7 puoi utilizzare uno dei seguenti:

tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;

tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;

Il primo animerà la tastiera fuori dallo schermo quando si scorre la vista tabella e il secondo nasconderà la tastiera come l'app Messaggi di serie.

Nota che questi sono da UIScrollView, che UITableVieweredita da.


simpatico. Sono riuscito a interromperlo scorrendo dall'alto verso il basso dello schermo fino a quando la tastiera ha iniziato a spostarsi verso il basso, quindi scorrendo di nuovo verso l'alto fino a quando la tastiera si è spostata leggermente verso l'alto, quindi lasciandola andare. lo scrollview non torna all'inizio come dovrebbe.
Sam

3

Prova questo:

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 è una sottoclasse di UIScrollView.

Il modo in cui l'ho fatto è stato ascoltare un evento di scorrimento dell'utente e poi resignFirstResponder. Ecco il metodo UIScrollViewDelegate da implementare nel codice;

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView

Quando mi avvicino a questo tipo di problemi, ho trovato che il modo migliore è ricercare i protocolli delegati per ogni oggetto e quelli delle classi padre (in questo caso UITableViewDelegate, UIScrollViewDelegate. Il numero di eventi che gli oggetti NS generano è piuttosto ampio e completo. anche più facile implementare un protocollo quindi sottoclassare qualsiasi cosa.


2

Ho avuto lo stesso problema ed ecco la mia soluzione, funziona perfettamente per me:

Nella vista o nel controller della vista che hai implementato <UITextFieldDelegate>

(Nel mio caso ho un custom UITableViewCellchiamato TextFieldCell),

Dichiara UITapGestureRecognizercome proprietà:

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

E inizializzalo nella tua vista / controller:

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

Nel - (void)textFieldDidBeginEditing:(UITextField *)textFieldmetodo, usa superViewper spostarti su tableView e chiama addGestureRecognizer:

[self.superview.superview addGestureRecognizer:gestureRecognizer];

E in - (void)textFieldDidEndEditing:(UITextField *)textField, è sufficiente rimuovere il riconoscimento dei gesti:

[self.superview.superview removeGestureRecognizer:gestureRecognizer];

Spero che sia d'aiuto.


Questo ha fatto per me. Grazie hac.jack
gilsaints88

2

Volevo che la mia cella aprisse la tastiera quando veniva selezionata una parte qualsiasi della cella e la chiudesse se facevi clic in un punto qualsiasi della cella. Per aprire la tastiera:

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

(NOTA: ho sottoclasse la cella ma puoi facilmente ottenere ciò nel tableView:didSelectRowAtIndexPath:metodo delegato di UITableView)

Ciò significava che con le soluzioni migliori se si faceva clic due volte sulla cella la tastiera tremava poiché, prima il riconoscimento dei gesti tentava di chiudere la tastiera, e in secondo luogo la cella veniva riselezionata e provava ad aprire la tastiera.

La soluzione è verificare se il clic si è verificato all'interno della cella attualmente selezionata:

- (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

Ho trovato una soluzione che funziona alla grande.

È necessario per utilizzare UIGestureRecognizerDelegate e il metodo - gestureRecognizer: shouldReceiveTouch: .

Aggiungere il riconoscimento dei gesti a TableView come segue:

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

Quindi, implementare il metodo delegato shouldReceiveTouch per rifiutare i tocchi eseguiti nella classe UITableViewCell. Il metodo hideKeyboard verrà chiamato solo quando il tocco è stato eseguito al di fuori della classe 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

UITableViewha una backgroundViewproprietà utile , con la quale ho ottenuto questo comportamento senza interferire con la selezione delle celle, come mostrato di seguito in Swift:

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


1

Semplicemente usando un UITapGestureRecognizer e cancelsTouchesInView = NOsignifica che i tocchi sulle celle e UITextViews attivano anche il nascondiglio. Questo non va bene se hai più UITextViews e tocchi quello successivo. La tastiera inizierà a nascondersi e quindi il successivo textView diventa il primoRisponditore e la tastiera diventa nuovamente visibile. Per evitare ciò, controlla la posizione del tocco e nascondi la tastiera solo se il tocco non è su una cella:

// 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)];
}

Per scrollViewWillBeginDragging:essere attivato, la scrollEnabledproprietà del tableView deve essereYES

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

Perfetto per me. Aggiunto un texbox alla cella tableview; se tocco fuori la tastiera congedo
Nicola

0

Perché vuoi creare una tabella piena di campi di testo? Dovresti utilizzare una visualizzazione dettagliata per ogni riga che contiene i campi di testo. Quando sposti la visualizzazione dettagliata, assicurati di chiamare "[myTextField getsFirstResponder]" in modo che l'utente possa iniziare a modificare con un solo clic dall'elenco della tabella.


L'app Contatti di Apple fa proprio questo. Non direi che sia pieno di campi di testo di per sé, ma li usa con buoni risultati.
Joe D'Andrea

2
La modifica del testo in linea in una visualizzazione tabella è molto più rapida e intuitiva rispetto alla visualizzazione delle visualizzazioni dettagliate per ogni campo di testo che l'utente desidera modificare ... basta chiedere al modulo HTML più vicino o ai campi di testo nei riquadri delle preferenze di iPhone o nell'app Contatti, oppure ecc. ecc. ecc ... è un vero peccato che Apple non abbia reso questo un tipo di cella standard, ma ci sono molte informazioni sul web su come raggiungere questo obiettivo.
glenc

0

Se sei disposto a sottoclassare (ugh!) La tua visualizzazione tabella, qualcosa del genere potrebbe funzionare:

- (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

Se vuoi chiudere la tastiera mentre è premuto il tasto Invio, puoi semplicemente aggiungere il seguente codice in textField dovrebbe restituire il metodo, ad esempio:

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

Alcuni campi di testo potrebbero avere una vista di selezione o un'altra come vista secondaria, quindi in quel caso il metodo sopra non funziona, quindi in quel caso dobbiamo utilizzare la classe UITapGestureRecognizer, ad esempio aggiungere il seguente frammento di codice al metodo viewDidLoad, ad esempio:

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

    [self.view addGestureRecognizer:tap];

Ora aggiungi semplicemente il risponditore di dimissioni al metodo di selezione, ovvero:

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

Spero che aiuti, grazie :)


0

Molte risposte interessanti. Vorrei compilare diversi approcci nella soluzione che ho ritenuto più adatta a uno scenario UITableView (è quello che uso di solito): quello che di solito vogliamo è fondamentalmente nascondere la tastiera in due scenari: toccando al di fuori degli elementi dell'interfaccia utente di testo, o scorrendo verso il basso / verso l'alto l'UITableView. Il primo scenario che possiamo aggiungere facilmente tramite TapGestureRecognizer e il secondo tramite il metodo UIScrollViewDelegate scrollViewWillBeginDragging :. Primo ordine del giorno, il metodo per nascondere la tastiera:

   /**
     *  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];

    }

Questo metodo rassegna qualsiasi interfaccia utente textField delle sottoview all'interno della gerarchia della vista UITableView, quindi è più pratico che dimettersi da ogni singolo elemento in modo indipendente.

Successivamente ci occupiamo di chiudere tramite un gesto Tap esterno, con:

- (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];

}

L'impostazione di tapGestureRecognizer.cancelsTouchesInView su NO serve per evitare che il gestureRecognizer sovrascriva il normale funzionamento interno di UITableView (ad esempio, per non interferire con la selezione della cella).

Infine, per gestire l'occultamento della tastiera durante lo scorrimento su / giù di UITableView, dobbiamo implementare il metodo scrollViewWillBeginDragging: protocollo UIScrollViewDelegate, come:

file .h

@interface MyViewController : UIViewController <UIScrollViewDelegate>

file .m

#pragma mark - UIScrollViewDelegate

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

Spero possa essere d'aiuto! =)


0

Ecco come ho finalmente realizzato le opere. Ho combinato suggerimenti e codici da risposte diverse. Caratteristiche: ignorare la tastiera, spostare i campi di testo sopra la tastiera durante la modifica e impostare il tipo di ritorno da tastiera "Avanti" e "Fine". SOSTITUISCI "..." con più campi

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

La risposta di @ mixca è molto utile, ma cosa succede se ho qualcosa di diverso da UITextField. Penso che il modo migliore per gestirlo cercando tutte le sottoview della vista principale con la funzione ricorsiva, controlla l'esempio di seguito

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

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

e puoi anche inserire questo metodo nella tua classe di utilità e puoi usare il gesto dal tocco come la risposta di @ mixca ..


0

Swift 4 / 4.2 / 5

Puoi anche chiudere la tastiera quando viene toccata una cella, prima di fare qualsiasi altra cosa.

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

0

tableView.keyboardDismissMode = .onDrag // .interactive

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.