Come ignorare la tastiera per UITextView con la chiave di ritorno?

Nella libreria di IB, l’introduzione ci dice che quando viene premuto il tasto Invio, la tastiera per UITextView scompare. Ma in realtà la chiave di ritorno può agire solo come \ n ‘.

Posso aggiungere un pulsante e usare [txtView resignFirstResponder] per hide la tastiera.

Ma c’è un modo per aggiungere l’azione per la chiave di ritorno nella tastiera in modo che non debba aggiungere UIButton ?

UITextView non ha alcun metodo che verrà chiamato quando l’utente preme la chiave di ritorno. Se vuoi che l’utente sia in grado di aggiungere solo una riga di testo, usa un UITextField . Colpire il ritorno e hide la tastiera per un UITextView non segue le linee guida dell’interfaccia.

Anche in questo caso, implementare textView:shouldChangeTextInRange:replacementText: metodo di UITextViewDelegate e verificare se il testo sostitutivo è \n , hide la tastiera.

Potrebbero esserci altri modi, ma non ne sono a conoscenza.

Ho pensato di pubblicare lo snippet qui invece:

Assicurati di dichiarare il supporto per il protocollo UITextViewDelegate .

 - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { if([text isEqualToString:@"\n"]) { [textView resignFirstResponder]; return NO; } return YES; } 

Aggiornamento Swift 4.0:

 func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { if text == "\n" { textView.resignFirstResponder() return false } return true } 

So che questo ha già avuto risposta, ma non mi piace usare la stringa letterale per la nuova riga, quindi ecco cosa ho fatto.

 - (BOOL)textView:(UITextView *)txtView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { if( [text rangeOfCharacterFromSet:[NSCharacterSet newlineCharacterSet]].location == NSNotFound ) { return YES; } [txtView resignFirstResponder]; return NO; } 

Aggiornamento Swift 4.0:

 func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { if (text as NSString).rangeOfCharacter(from: CharacterSet.newlines).location == NSNotFound { return true } txtView.resignFirstResponder() return false } 

So che questo è stato risposto molte volte, ma qui ci sono i miei due centesimi per il problema.

Ho trovato le risposte di samvermette e ribeto davvero utili, e anche il commento di maxpower nella risposta di ribeto . Ma c’è un problema con questi approcci. Il problema che opaco cita nella risposta di samvermette ed è che se l’utente vuole incollare qualcosa con un’interruzione di riga al suo interno, la tastiera si hidebbe senza incollare nulla.

Quindi il mio approccio è una combinazione delle tre soluzioni sopra menzionate e solo il controllo se la stringa immessa è una nuova riga quando la lunghezza della stringa è 1, quindi ci assicuriamo che l’utente stia digitando invece di incollare.

Ecco cosa ho fatto:

 - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { NSRange resultRange = [text rangeOfCharacterFromSet:[NSCharacterSet newlineCharacterSet] options:NSBackwardsSearch]; if ([text length] == 1 && resultRange.location != NSNotFound) { [textView resignFirstResponder]; return NO; } return YES; } 

Un modo più elegante è quello di chiudere la tastiera quando l’utente tocca da qualche parte al di fuori del frame della tastiera.

Per prima cosa, imposta la vista ViewController alla class “UIControl” nella finestra di ispezione dell’identity framework in UIBuilder. Controllo: trascinare la vista nel file di intestazione di ViewController e collegarlo come un’azione all’evento come Ritouch interno, ad esempio:

ViewController.h

 -(IBAction)dismissKeyboardOnTap:(id)sender; 

Nel file ViewController principale, ViewController.m:

 -(IBAction)dismissKeyboardOnTap:(id)sender { [[self view] endEditing:YES]; } 

È ansible richiedere un doppio touch o un touch lungo utilizzando tecniche simili. Potrebbe essere necessario impostare ViewController come UITextViewDelegate e connettere TextView a ViewController. Questo metodo funziona sia per UITextView che per UITextField.

Fonte: Big Nerd Ranch

EDIT: Vorrei anche aggiungere che se si utilizza un UIScrollView, la tecnica di cui sopra potrebbe non funzionare facilmente attraverso l’Interface Builder. In tal caso, è ansible utilizzare un UIGestureRecognizer e chiamare invece il metodo [[self view] endEditing: YES] al suo interno. Un esempio potrebbe essere:

 -(void)ViewDidLoad{ .... UITapGestureRecognizer *tapRec = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)]; [self.view addGestureRecognizer: tapRec]; .... } -(void)tap:(UITapGestureRecognizer *)tapRec{ [[self view] endEditing: YES]; } 

Quando l’utente tocca la tastiera e non tocca uno spazio di immissione, la tastiera verrà chiusa.

Aggiungi questo metodo nel tuo controller di visualizzazione.

Swift :

 func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool { if text == "\n" { textView.resignFirstResponder() return false } return true } 

Questo metodo può anche essere utile per te:

 /** Dismiss keyboard when tapped outside the keyboard or textView :param: touches the touches :param: event the related event */ override func touchesBegan(touches: NSSet, withEvent event: UIEvent) { if let touch = touches.anyObject() as? UITouch { if touch.phase == UITouchPhase.Began { textField?.resignFirstResponder() } } } 
 -(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { if([text isEqualToString:@"\n"]) [textView resignFirstResponder]; return YES; } yourtextView.delegate=self; 

Aggiungi anche UITextViewDelegate

Non dimenticare di confermare il protocollo

Se non hai aggiunto if([text isEqualToString:@"\n"]) non puoi modificare

C’è un’altra soluzione durante l’utilizzo con uitextview, È ansible aggiungere barra degli strumenti come InputAccessoryView in “textViewShouldBeginEditing”, e dal pulsante di questa barra degli strumenti è ansible chiudere la tastiera, il codice per questo è il seguente:

In viewDidLoad

 toolBar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 44)]; //toolbar is uitoolbar object toolBar.barStyle = UIBarStyleBlackOpaque; UIBarButtonItem *btnDone = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(btnClickedDone:)]; [toolBar setItems:[NSArray arrayWithObject:btnDone]]; 

Nel metodo textviewdelegate

 - (BOOL)textViewShouldBeginEditing:(UITextView *)textView { [textView setInputAccessoryView:toolBar]; return YES; } 

In azione di Button Done che è nella barra degli strumenti segue:

 -(IBAction)btnClickedDone:(id)sender { [self.view endEditing:YES]; } 

Ho trovato la risposta di josebama come la risposta più completa e pulita disponibile in questa discussione.

Di seguito è riportata la syntax Swift 3 :

 func textView(_ textView: UITextView, shouldChangeTextIn _: NSRange, replacementText text: String) -> Bool { let resultRange = text.rangeOfCharacter(from: CharacterSet.newlines, options: .backwards) if text.characters.count == 1 && resultRange != nil { textView.resignFirstResponder() // Do any additional stuff here return false } return true } 

Proprio come un commento opaco a samvermette, non mi piace l’idea di rilevare “\ n”. La chiave “return” è presente per un motivo in UITextView, ovvero per passare alla riga successiva, ovviamente.

La soluzione migliore a mio parere è quella di imitare l’app per messaggi iPhone, che consiste nell’aggiungere la barra degli strumenti (e il pulsante) sulla tastiera.

Ho ricevuto il codice dal seguente post sul blog:

http://www.iosdevnotes.com/2011/02/iphone-keyboard-toolbar/

passi:

-Aggiungi barra degli strumenti al tuo file XIB – imposta l’altezza a 460

-Aggiungi l’object del pulsante della barra degli strumenti (se non è già stato aggiunto). Se è necessario allineare a destra, aggiungere anche l’elemento pulsante barra flessibile a XIB e spostare la voce del pulsante della barra degli strumenti

-Creazione di azioni che collegano l’elemento del tuo pulsante a resignFirstResponder come segue:

 - (IBAction)hideKeyboard:(id)sender { [yourUITextView resignFirstResponder]; } 

-Poi:

 - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; } - (void)keyboardWillShow:(NSNotification *)notification { [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:0.3]; CGRect frame = self.keyboardToolbar.frame; frame.origin.y = self.view.frame.size.height - 260.0; self.keyboardToolbar.frame = frame; [UIView commitAnimations]; } - (void)keyboardWillHide:(NSNotification *)notification { [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:0.3]; CGRect frame = self.keyboardToolbar.frame; frame.origin.y = self.view.frame.size.height; self.keyboardToolbar.frame = frame; [UIView commitAnimations]; } 

Ho appena risolto questo problema in un modo diverso.

  • Crea un pulsante che verrà posizionato in background
  • Da Impostazioni attributi, cambia il tipo di pulsante in personalizzato e rende il pulsante trasparente.
  • Espandi il pulsante per coprire l’intera vista e assicurati che il pulsante sia dietro a tutti gli altri oggetti. Un modo semplice per farlo è quello di trascinare il pulsante nella parte superiore della visualizzazione elenco nella vista
  • Control trascina il pulsante sul file viewController.h e crea un’azione (Sent Event: Touch Up Inside) come:

     (IBAction)ExitKeyboard:(id)sender; 
  • In ViewController.m dovrebbe apparire come:

     (IBAction)ExitKeyboard:(id)sender { [self.view endEditing:TRUE]; } 
  • Esegui app e quando fai clic lontano da TextView, la tastiera scompare

Aggiungi un osservatore in viewDidLoad

 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(textViewKeyPressed:) name: UITextViewTextDidChangeNotification object: nil]; 

e quindi utilizzare il selettore per verificare “\ n”

 -(void) textViewKeyPressed: (NSNotification*) notification { if ([[[notification object] text] hasSuffix:@"\n"]) { [[notification object] resignFirstResponder]; } } 

Usa “\ n” e non controlla specificatamente la chiave di ritorno, ma penso che sia OK.

AGGIORNARE

Vedere la risposta di ribto al di sotto della quale utilizza [NSCharacterSet newlineCharacterSet] al posto di \n

Utilizzo del controller di navigazione per ospitare una barra per chiudere la tastiera:

nel file .h:

 UIBarButtonItem* dismissKeyboardButton; 

nel file .m:

 - (void)viewDidLoad { dismissKeyboardButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(dismissKeyboard)]; } -(void)textViewDidBeginEditing:(UITextView *)textView { self.navigationItem.rightBarButtonItem = dismissKeyboardButton; } -(void)textFieldDidBeginEditing:(UITextField *)textField { self.navigationItem.rightBarButtonItem = dismissKeyboardButton; } -(void)dismissKeyboard { [self.textField resignFirstResponder]; [self.textView resignFirstResponder]; //or replace this with your regular right button self.navigationItem.rightBarButtonItem = nil; } 

Prova questo :

  - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{ if ([text isEqualToString:@"\n"]) { [self.view endEditing:YES]; } return YES; } 

// Puoi usare questo …

Passaggio 1. Il primo passo è assicurarsi di dichiarare il supporto per il protocollo UITextViewDelegate . Questo è fatto nel tuo file di intestazione, come esempio qui è l’intestazione chiamata

EditorController.h:

 @interface EditorController : UIViewController { UITextView *messageTextView; } @property (nonatomic, retain) UITextView *messageTextView; @end 

Passaggio 2. Successivamente sarà necessario registrare il controller come delegato di UITextView. Continuando dall’esempio sopra, ecco come ho inizializzato UITextView con EditorController come delegato …

 - (id) init { if (self = [super init]) { // define the area and location for the UITextView CGRect tfFrame = CGRectMake(10, 10, 300, 100); messageTextView = [[UITextView alloc] initWithFrame:tfFrame]; // make sure that it is editable messageTextView.editable = YES; // add the controller as the delegate messageTextView.delegate = self; } 

Passo 3. E ora il pezzo finale del puzzle è di agire in risposta al messaggio shouldCahngeTextInRange come segue:

 - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { // Any new character added is passed in as the "text" parameter if ([text isEqualToString:@"\n"]) { // Be sure to test for equality using the "isEqualToString" message [textView resignFirstResponder]; // Return FALSE so that the final '\n' character doesn't get added return FALSE; } // For any other character return TRUE so that the text gets added to the view return TRUE; } 

veloce

 func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool { if text == "\n" { textView.resignFirstResponder() } return true } 

e configurare

codice SWIFT

Implementa UITextViewDelegate nella tua class / Visualizza in questo modo:

 class MyClass: UITextViewDelegate { ... 

imposta il delegato textView su self

 myTextView.delegate = self 

E quindi attuare quanto segue:

  func textViewDidChange(_ textView: UITextView) { if textView.text.characters.count >= 1 { if let lastChar = textView.text.characters.last { if(lastChar == "\n"){ textView.text = textView.text.substring(to: textView.text.index(before: textView.text.endIndex)) textView.resignFirstResponder() } } } } 

EDIT Ho aggiornato il codice perché non è mai una buona idea cambiare l’input dell’utente in un campo di testo per un workarround e non reimpostare lo stato dopo che il codice hack è stato completato.

Puoi anche hide la tastiera quando tocchi la schermata di visualizzazione:

 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch * touch = [touches anyObject]; if(touch.phase == UITouchPhaseBegan) { [txtDetail resignFirstResponder]; } } 

Risposta rapida:

 override func viewDidLoad() { super.viewDidLoad() let tapGestureReconizer = UITapGestureRecognizer(target: self, action: "tap:") view.addGestureRecognizer(tapGestureReconizer) } func tap(sender: UITapGestureRecognizer) { view.endEditing(true) } 

Ho usato questo codice per cambiare il risponditore.

  - (BOOL)textView:(UITextView*) textView shouldChangeTextInRange: (NSRange) range replacementText: (NSString*) text { if ([text isEqualToString:@"\n"]) { //[textView resignFirstResponder]; //return YES; NSInteger nextTag = textView.tag + 1; // Try to find next responder UIResponder* nextResponder = [self.view viewWithTag:nextTag]; if (nextResponder) { // Found next responder, so set it. [nextResponder becomeFirstResponder]; } else { // Not found, so remove keyboard. [textView resignFirstResponder]; } return NO; return NO; } return YES; } 

Ok. Tutti hanno dato risposte con trucchi, ma penso che il modo giusto per ottenere questo risultato sia vicino

Collegamento dell’azione seguente all’evento ” Esito all’uscita ” in Interface Builder . (fare clic con il tasto destro del mouse su TextField e trascinare tenendo premuto Cntrl da ” Fine all’uscita ” al seguente metodo.

 -(IBAction)hideTheKeyboard:(id)sender { [self.view endEditing:TRUE]; } 
 - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { if (range.length==0) { if ([text isEqualToString:@"\n"]) { [txtView resignFirstResponder]; if(textView.returnKeyType== UIReturnKeyGo){ [self PreviewLatter]; return NO; } return NO; } } return YES; } 
 + (void)addDoneButtonToControl:(id)txtFieldOrTextView { if([txtFieldOrTextView isKindOfClass:[UITextField class]]) { txtFieldOrTextView = (UITextField *)txtFieldOrTextView; } else if([txtFieldOrTextView isKindOfClass:[UITextView class]]) { txtFieldOrTextView = (UITextView *)txtFieldOrTextView; } UIToolbar* numberToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, [Global returnDeviceWidth], 50)]; numberToolbar.barStyle = UIBarStyleDefault; UIBarButtonItem *btnDone = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"btn_return"] style:UIBarButtonItemStyleBordered target:txtFieldOrTextView action:@selector(resignFirstResponder)]; numberToolbar.items = [NSArray arrayWithObjects:btnDone,nil]; [numberToolbar sizeToFit]; if([txtFieldOrTextView isKindOfClass:[UITextField class]]) { ((UITextField *)txtFieldOrTextView).inputAccessoryView = numberToolbar; } else if([txtFieldOrTextView isKindOfClass:[UITextView class]]) { ((UITextView *)txtFieldOrTextView).inputAccessoryView = numberToolbar; } } 

La domanda chiede come farlo con la chiave di ritorno, ma penso che questo potrebbe aiutare qualcuno con l’intento di far scomparire la tastiera quando si utilizza UITextView:

 @IBOutlet weak var textView: UITextView! private func addToolBarForTextView() { let textViewToolbar: UIToolbar = UIToolbar() textViewToolbar = UIBarStyle.Default textViewToolbar = [ UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.Done, target: self, action: #selector(self.cancelInput)), UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: self, action: nil), UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.Done, target: self, action: #selector(self.doneInput)) ] textViewToolbar() self.textView.inputAccessoryView = textViewToolbar //do it for every relevant textView if there are more than one } func doneInput() { self.textView.resignFirstResponder() } func cancelInput() { self.textView.text = "" self.textView.resignFirstResponder() } 

Chiama addToolBarForTextView () nel viewDidLoad o in qualche altro metodo del ciclo di vita.

Sembra che fosse la soluzione perfetta per me.

Saluti,

Murat

 -(BOOL)textFieldShouldReturn:(UITextField *)textField; // called from textfield (keyboard) -(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text; // good tester function - thanks 

So che non è la risposta esatta a questa domanda, ma ho trovato questo thread dopo aver cercato internet per una risposta. Presumo che gli altri condividano questa sensazione.

Questa è la mia varianza di UITapGestureRecognizer che trovo affidabile e facile da usare: basta impostare il delegato di TextView su ViewController.

Invece di ViewDidLoad aggiungo UITapGestureRecognizer quando TextView diventa attivo per la modifica:

 -(void)textViewDidBeginEditing:(UITextView *)textView{ _tapRec = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)]; [self.view addGestureRecognizer: _tapRec]; NSLog(@"TextView Did begin"); } 

Quando touch fuori da TextView, la visualizzazione termina la modalità di modifica e UITapGestureRecognizer si rimuove da solo, così posso continuare a interagire con altri controlli nella vista.

 -(void)tap:(UITapGestureRecognizer *)tapRec{ [[self view] endEditing: YES]; [self.view removeGestureRecognizer:tapRec]; NSLog(@"Tap recognized, tapRec getting removed"); } 

Spero che aiuti. Sembra così ovvio ma non ho mai visto questa soluzione da nessuna parte sul web – sto facendo qualcosa di sbagliato?

Non dimenticare di impostare il delegato per il textView – altrimenti resignfirsupporter non funzionerà.

Prova questo .

 NSInteger lengthOfText = [[textView.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length]; 

Per Xcode 6.4., Swift 1.2. :

  override func touchesBegan(touches: Set, withEvent event: UIEvent) { super.touchesBegan(touches, withEvent: event) if let touch = touches.first as? UITouch { self.meaningTextview.resignFirstResponder() } } 

Il mio hack per questo:

1- creare un pulsante che copra l’intera vista; 2- mandalo sullo sfondo della tua vista, 3- cambia Tipo da “Round Rect” a “Custom” in Attribute Inspector, 4 crea un’azione 5 implementa il metodo action:

 - (IBAction)bgTouched:(id)sender { //to dismiss keyboard on bg btn pressed [_userInput resignFirstResponder]; } 

dove _userInput è la tua presa TextField