2015-10-07 20 views
9

Link per la domanda precedente: UITextField text jumpsUITextField testo salti iOS 9

Brevemente: Ho ViewController con 2 UITextField elementi. Quando loginField è firstResponder, dopo

self.passwordField.becomeFirstResponder() 

testo in campo di accesso salta alto a sinistra e viceversa. E per di più strano: questo glitch riproduce solo la prima volta, quindi è necessario ricreare ViewController a osservare questo comportamento

Qui è il video del problema tecnico http://tinypic.com/player.php?v=6nsemw%3E&s=8#.VgVb3cuqpHx

ho finito con questo (non funziona per iOS 9) :

func textFieldShouldReturn(textField: UITextField) -> Bool { 
    if textField === self.loginField { 
     self.loginField.resignFirstResponder() 
     // Shitty workaround. Hi, Apple! 
     self.loginField.setNeedsLayout() 
     self.loginField.layoutIfNeeded() 

     self.passwordField.becomeFirstResponder() 
     return false 
    } 

    return true 
} 

C'è qualcuno che è stato stucked con questo errore? Eventuali suggerimenti?

notifiche della tastiera gestori

mio punto di vista principale è UIScrollView, per il quale a cambiare lo spazio in basso a Superview, così l'utente può scorrere tutti i contenuti anche quando la tastiera è mostrato

func keyboardWillShow(notification : NSNotification) { 
    let keyboardInfo = notification.userInfo! 
    let keyboardFrame = keyboardInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue 
    let animDuration = keyboardInfo[UIKeyboardAnimationDurationUserInfoKey]!.doubleValue! 

    UIView.animateWithDuration(animDuration, animations: { 
     self.scrollViewBottom.constant = keyboardFrame.height 
     self.view.layoutIfNeeded() 

     let offsetY = CGRectGetMaxY(self.loginButton.frame) + 10 - self.scrollView.frame.height 
     if offsetY > 0 { 
      self.scrollView.contentOffset = CGPointMake(0, offsetY) 
     } 
    }) 
} 

func keyboardWillHide(notification : NSNotification) { 
    self.scrollViewBottom.constant = 0 
    self.view.layoutIfNeeded() 
} 

Come ho scoperto le notifiche della tastiera in iOS7, 8 e 9 sono molto diversi. Quindi, in iOS 9 le notifiche vengono inviate mentre si modifica FirstResponder anche se la tastiera non mostra/nasconde. Inoltre, quando cambio FirstResponder toccando su textField (non toccando Next sulla tastiera che viene gestito dal mio codice), c'è solo la notifica KeyboardWillShow e nessun KeyboardWillHide. E per quanto riguarda me, userInfo ha alcuni valori telaio spazzatura, qui sta il login quando si cambia first responder tramite pulsante accanto (funziona bene, senza difetti):

2015-10-07 12: 54: 13.870 keyboardWillHide: [ UIKeyboardFrameBeginUserInfoKey: NSRect: {{0, 352}, {320, 216}}, UIKeyboardCenterBeginUserInfoKey: NSPoint: {160, 460}, UIKeyboardFrameEndUserInfoKey: NSRect: {{0, 568}, {320, 216}}, UIKeyboardCenterEndUserInfoKey : NSPoint: {160, 676}, UIKeyboardAnimationDurationUserInfoKey: 0.25, UIKeyboardIsLocalUserInfoKey: 1, UIKeyboardBoundsUserInfoKey: NSRect: {{0, 0}, {320, 216}}, UIKeyboardAnimationCurveUserInfoKey: 7] 2015/10/07 12: 54: 13,896 keyboardWillShow: [UIKeyboardFrameBeginUserInfoKey: NSRect: {{0, 352}, {320, 216}}, UIKeyboardCenterBeginUserInfoKey: NSPoint: {160, 460}, UIKeyboardFrameEndUserInfoKey: NSRect : {{0, 352}, {320, 216}}, UIKeyboardCenterEndUserInfoKey: NSPoint: {160, 460}, UIKeyboardAnimationDurationUserInfoKey: 0.25, UIKeyboardIsLocalUserInfoKey: 1, UIKeyboardBoundsUserInfoKey: NSRect: {{0, 0}, {320 , 216}}, UIKeyboardAnimationCurveUserInfoKey: 7]

E qui viene il login quando si tocca sul secondo textField:

2015-10-07 12:55:13.879 keyboardWillShow: [UIKeyboardFrameBeginUserInfoKey: NSRect: {{0, 352}, {320, 216}}, UIKeyboardCenterBeginUserInfoKey: NSPoint: {160, 460}, UIKeyboardFrameEndUserInfoKey: NSRect: {{0, 352}, {320, 216}}, UIKeyboardCenterEndUserInfoKey: NSPoint: {160, 460},
UIKeyboardAnimationDurationUserInfoKey: 0.25, UIKeyboardIsLocalUserInfoKey: 1, UIKeyboardBoundsUserInfoKey: NSRect: {{0, 0}, {320, 216}}, UIKeyboardAnimationCurveUserInfoKey: 7]

Risoluzione

Ho scoperto che ho un altro controller per tastiera che riceve le notifiche della tastiera e crea alcune animazioni. Ecco dove sta il problema

+1

Come stai gestendo la tastiera? Hai delle notifiche registrate per la tastiera visualizzata/nascosta? Se sì, puoi pubblicare il codice che cosa fai lì? – haluzak

+0

Tnx per l'aiuto, controlla il post modificato – user3237732

+1

Si sta per nascondere la notifica perché si chiama resignFirstResponder() prima di diventareFirstResponder(), il "salto" è causato dall'animazione in keyboardWillShow() – haluzak

risposta

7

In base alla tua domanda modificato posso vedere questo, quando si tocca il pulsante successivo sulla tastiera:

  1. si sta chiamando resignFirstResponder() e poi becomeFirstResponder(). Questo chiama la notifica keyboardWillHide e quindi la notifica keyboardWillShow
  2. In keyboardWillHide si ha self.view.layoutIfNeeded() quale layout la vista (e le sottoview - campi di testo) senza animazione.

A causa di questo layout del campo di testo è "fisso" e quando lo si fa animazione nella keyboardWillShow il testo nel campo di testo non "saltare" più, perché hai fatto layout in keyboardWillHide.

Ma quando si tocca un altro campo di testo, viene chiamato solo keyboardWillShow, il layout non viene "riparato" nel campo di testo e quando si anima la vista, il testo esegue un'animazione "salta".

Ecco perché non salta quando si tocca la tastiera successiva, ma salta quando si tocca semplicemente un altro campo di testo.

quindi consiglierei di cambiare a questo:

func textFieldShouldReturn(textField: UITextField) -> Bool { 
    if textField === self.loginField { 
     self.passwordField.becomeFirstResponder() 
     return false 
    } 

    return true 
} 

func keyboardWillShow(notification : NSNotification) { 
    let keyboardInfo = notification.userInfo! 
    let keyboardFrame = keyboardInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue 
    let animDuration = keyboardInfo[UIKeyboardAnimationDurationUserInfoKey]!.doubleValue! 

    self.loginField.layoutIfNeeded() 
    self.passwordField.layoutIfNeeded() 

    if keyboardFrame.height != self.scrollViewBottom.constant { 
     UIView.animateWithDuration(animDuration, animations: { 
      self.scrollViewBottom.constant = keyboardFrame.height 
      self.view.layoutIfNeeded() 

      let offsetY = CGRectGetMaxY(self.loginButton.frame) + 10 - self.scrollView.frame.height 
      if offsetY > 0 { 
       self.scrollView.contentOffset = CGPointMake(0, offsetY) 
      } 
     }) 
    } 
} 
+0

purtroppo, che non ha aiutato – user3237732

+0

ho anche commentato i miei gestori di notifica della tastiera - problema tecnico ancora persistono – user3237732

+0

avvolto come questo UIView.performWithoutAnimation ({ self.loginField.layoutIfNeeded() self.passwordField.layoutIfNeeded() }) e non funziona – user3237732

6

Tnx a haluzak:

func textFieldShouldReturn(textField: UITextField) -> Bool { 
    if textField === self.loginField { 
     self.passwordField.becomeFirstResponder() 
     return false 
    } 

    return true 
} 

func keyboardWillShow(notification : NSNotification) { 
    let keyboardInfo = notification.userInfo! 
    let keyboardFrame = keyboardInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue 
    let animDuration = keyboardInfo[UIKeyboardAnimationDurationUserInfoKey]!.doubleValue! 

    UIView.performWithoutAnimation({ 
     self.loginField.layoutIfNeeded() 
     self.passwordField.layoutIfNeeded() 
    }) 

    if keyboardFrame.height != self.scrollViewBottom.constant { 
     UIView.animateWithDuration(animDuration, animations: { 
      self.scrollViewBottom.constant = keyboardFrame.height 
      self.view.layoutIfNeeded() 

      let offsetY = CGRectGetMaxY(self.loginButton.frame) + 10 - self.scrollView.frame.height 
      if offsetY > 0 { 
       self.scrollView.contentOffset = CGPointMake(0, offsetY) 
      } 
     }) 
    } 
} 
+2

La parte 'performWithoutAnimation' è stata la chiave per me. – teradyl

0

inserire questo codice nella vostra tastiera mostrerà la notifica, prima di fare qualsiasi animazioni:

UIView.performWithoutAnimation({ 
    self.yourTextField1.layoutIfNeeded() 
    self.yourTextField2.layoutIfNeeded() 
    //etc. 
}) 
2

Ho affrontato lo stesso problema, quando stavo cercando di cambiare il primo soccorritore. C'è una soluzione migliore per questo problema. È sufficiente implementare la sottoclasse UITextField e utilizzarla in luoghi in cui è possibile animare il campo di testo (tastiera, commutazione prima risposta e così via).

@interface UITextFieldFixed : UITextField 

@end 

@implementation UITextFieldFixed 

- (BOOL)resignFirstResponder 
{ 
    BOOL result = [super resignFirstResponder]; 
    [self setNeedsLayout]; 
    [self layoutIfNeeded]; 
    return result; 
} 

@end 

Maggiori informazioni su problema: https://github.com/foundry/UITextFieldBug

Copia e incolla per Swift3 ...

class UITextFieldFixed: UITextField { 
    override func resignFirstResponder() -> Bool { 
     let r = super.resignFirstResponder() 
     self.setNeedsLayout() 
     self.layoutIfNeeded() 
     return r 
    } 
} 
+0

Questo è fantastico, Timur, grazie. Ho incollato lo stesso in Swift3 - sentiti libero di modificare o annullare, Timur! – Fattie

+0

@JoeBlow ringraziamenti! –

+0

inviato bounty per un'ottima risposta qui – Fattie

0

Ecco semplice codice è necessario scrivere per smettere di saltare di testo. Questo è lavoro per me.

func textFieldDidEndEditing(_ textField: UITextField) { // Workaround for the jumping text bug. textField.resignFirstResponder() textField.layoutIfNeeded() }