2015-10-07 17 views
9

Link zur Verwendung vorherige Frage: UITextField text jumpsUITextField Text springt iOS 9

Kurz: Ich habe ViewController mit 2 UITextField Elemente. Wenn loginField ist firstResponder nach

self.passwordField.becomeFirstResponder() 

Text in Login-Feld auf die linke obere Ecke springt und zurück. Und was mehr ist seltsam: diese Panne nur erstes Mal wiedergibt, dann müssen Sie ViewController neu dieses Verhalten

Hier wird Video von der Panne zu beobachten http://tinypic.com/player.php?v=6nsemw%3E&s=8#.VgVb3cuqpHx

ich damit endete (funktioniert nicht für 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 
} 

Gibt es jemanden, der mit diesem Fehler stecken geblieben ist? Irgendwelche Vorschläge?

Keyboard Benachrichtigungen Handler

Meine Hauptansicht ist UIScrollView, für die ich unten Raum Super ändern, so Benutzer kann den Inhalt blättern, auch wenn Tastatur

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

gezeigt, wie ich Tastatur Mitteilungen entdeckt In iOS7 unterscheiden sich 8 und 9 sehr. In iOS 9 werden also Benachrichtigungen gesendet, wenn FirstResponder geändert wird, auch wenn die Tastatur nicht ein-/ausblenden wird. Wenn ich firstResponder durch Antippen von textField ändere (ohne auf die Tastatur zu tippen, die von meinem Code gehandhabt wird), gibt es nur eine KeyboardWillShow-Benachrichtigung und kein KeyboardWillHide. Und was mich betrifft, hat userinfo einige Werte trash Rahmen, hier einloggen, wenn Ersthelfer Ändern nächste Taste (funktioniert ok, ohne Pannen):

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]

Und hier einloggen, wenn ich auf dem zweiten Textfield tippen:

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]

Auflösung

Ich entdeckte, dass ich einen anderen Tastatur-Controller habe, der Tastaturbenachrichtigungen empfängt und einige Animationen macht. Das ist, wo das Problem

+1

Wie gehen Sie mit der Tastatur um? Haben Sie registrierte Benachrichtigungen für die Tastatur erscheint/verstecken? Wenn ja, kannst du den Code posten, was du dort machst? – haluzak

+0

Tnx für die Hilfe, überprüfen Sie den bearbeiteten Post – user3237732

+1

Sie erhalten wird verbergen Benachrichtigung, weil Sie ResignFirstResponder() vor BeeFirstResponder() aufrufen, das "Springen" wird durch die Animation in KeyboardWillShow() verursacht – haluzak

Antwort

7

Basierend auf Ihrer editierten Frage liegt kann ich sehen, das, wenn Sie die nächste Taste auf der Tastatur tippen:

  1. Du nennst resignFirstResponder() und dann becomeFirstResponder(). Dies ruft keyboardWillHide Benachrichtigung und dann keyboardWillShow Benachrichtigung
  2. In keyboardWillHide haben Sie self.view.layoutIfNeeded() welche Layouts die Ansicht (und Subviews - Textfelder) ohne Animation.

Aufgrund dieser das Textfeld Layout ist „fixiert“ und wenn Sie Animation tun in keyboardWillShow der Text in Textfeld mehr nicht „springen“, weil Sie das Layout tat in keyboardWillHide.

Wenn Sie jedoch nur auf ein anderes Textfeld tippen, wird nur keyboardWillShow aufgerufen, das Layout ist nicht im Textfeld "fixiert" und wenn Sie die Ansicht animieren, führt der Text eine "Sprung" -Animation durch.

Deshalb springt es nicht, wenn Sie auf der Tastatur tippen, aber es springt, wenn Sie einfach auf ein anderes Textfeld tippen.

So würde ich raten, es zu, dies zu ändern:

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

leider die nicht – user3237732

+0

helfen habe ich auch meine Tastatur Benachrichtigung Handler kommentiert - Glitch bestehen noch – user3237732

+0

wie diese UIView.performWithoutAnimation Wrapped ({ self.loginField.layoutIfNeeded() self.passwordField.layoutIfNeeded() }) und nicht es funktioniert – user3237732

6

Tnx zu 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

Der 'performWithoutAnimation' Teil war der Schlüssel für mich. – teradyl

0

Setzen Sie diesen Code in Ihrer Tastatur Benachrichtigung zeigen, bevor Sie irgendwelche Animationen tun:

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

Ich habe dasselbe Problem konfrontiert, als ich versuchte, Ersthelfer zu ändern. Es gibt eine bessere Lösung für dieses Problem. Implementiere einfach die UITextField-Unterklasse und verwende sie an Orten, an denen dein Textfeld animiert werden kann (Tastatur, erste Antwortschaltung usw.).

@interface UITextFieldFixed : UITextField 

@end 

@implementation UITextFieldFixed 

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

@end 

Mehr Infos über Ausgabe: https://github.com/foundry/UITextFieldBug

Kopieren für swift3 ...

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

Das ist fantastisch Timur, danke. Ich habe das selbe in Swift3 eingefügt - zögern Sie nicht, Timur zu bearbeiten oder rückgängig zu machen! – Fattie

+0

@JoeBlow danke! –

+0

geschickt Bounty für große Antwort hier – Fattie

0

ist hier einfach Code, den Sie für Stop-Springen von Text schreiben müssen. Das ist Arbeit für mich.

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