1792 Stimmen

Wie kann ich ein UITextField nach oben bewegen, wenn die Tastatur vorhanden ist - beim Start der Bearbeitung?

Mit dem iOS SDK:

Ich habe eine UIView con UITextField s, die eine Tastatur aufrufen. Ich brauche es in der Lage zu sein:

  1. Erlaubt das Scrollen des Inhalts der UIScrollView um die anderen Textfelder zu sehen, sobald die Tastatur eingeblendet wird

  2. Automatisches "Springen" (durch Scrollen nach oben) oder Verkürzen

Ich weiß, dass ich eine UIScrollView . Ich habe versucht, die Klasse meiner UIView を、その UIScrollView aber ich kann die Textfelder immer noch nicht nach oben oder unten verschieben.

Benötige ich sowohl eine UIView und eine UIScrollView ? Passt das eine in das andere?

Was muss implementiert werden, um automatisch zum aktiven Textfeld zu blättern?

Idealerweise wird die Einrichtung der Komponenten so weit wie möglich im Interface Builder vorgenommen. Ich möchte nur Code für das schreiben, was ich brauche.

Anmerkung: Die UIView (o UIScrollView ), mit dem ich arbeite, wird über eine Registerkartenleiste angezeigt ( UITabBar ), die wie gewohnt funktionieren muss.


Ich füge die Bildlaufleiste nur dann hinzu, wenn die Tastatur angezeigt wird. Auch wenn es nicht benötigt wird, habe ich das Gefühl, dass es eine bessere Schnittstelle bietet, weil der Benutzer dann scrollen und Textfelder ändern kann, zum Beispiel.

Ich habe es so hinbekommen, dass ich die Rahmengröße der UIScrollView wenn die Tastatur auf und ab geht. Ich benutze einfach:

-(void)textFieldDidBeginEditing:(UITextField *)textField {
    //Keyboard becomes visible
    scrollView.frame = CGRectMake(scrollView.frame.origin.x,
                                  scrollView.frame.origin.y,
    scrollView.frame.size.width,
    scrollView.frame.size.height - 215 + 50);   // Resize
}

-(void)textFieldDidEndEditing:(UITextField *)textField {
    // Keyboard will hide
    scrollView.frame = CGRectMake(scrollView.frame.origin.x,
                                  scrollView.frame.origin.y,
                                  scrollView.frame.size.width,
                                  scrollView.frame.size.height + 215 - 50); // Resize
}

Allerdings werden dadurch die unteren Textfelder nicht automatisch nach oben verschoben oder im sichtbaren Bereich zentriert, was ich eigentlich gerne hätte.

0 Stimmen

Sie können das Textfeld animieren, so dass sich das Textfeld bewegt, wenn die Tastatur hochkommt

7 Stimmen

Sehen Sie sich das an. Kein Ärger für Sie. TPKeyboardVermeiden

24 Stimmen

Das ist von Apple dokumentiert, und ich denke, das ist der beste Weg: developer.apple.com/library/ios/#documentation/StringsTextFonts/

121voto

Für Universelle Lösung Hier war mein Ansatz für die Umsetzung IQKeyboardManager .

enter image description here

Schritt1:- I Hinzufügen von globalen Benachrichtigungen über UITextField , UITextView et UIKeyboard in einer Singleton-Klasse. Ich nenne es IQKeyboardManager .

Schritt2:- Wenn gefunden UIKeyboardWillShowNotification , UITextFieldTextDidBeginEditingNotification o UITextViewTextDidBeginEditingNotification Benachrichtigungen, versuche ich, die topMostViewController Instanz aus der UIWindow.rootViewController Hierarchie. Um richtig aufdecken zu können UITextField / UITextView darauf, topMostViewController.view Der Rahmen muss angepasst werden.

Schritt3:- Ich habe eine voraussichtliche Bewegungsdistanz von topMostViewController.view in Bezug auf die zuerst beantwortete UITextField / UITextView .

Schritt4:- Ich bin umgezogen topMostViewController.view.frame nach oben/unten entsprechend der zu erwartenden Fahrstrecke.

Schritt5:- Wenn gefunden UIKeyboardWillHideNotification , UITextFieldTextDidEndEditingNotification o UITextViewTextDidEndEditingNotification Benachrichtigung, versuche ich erneut, die topMostViewController Instanz aus der UIWindow.rootViewController Hierarchie.

Schritt6:- Ich habe eine gestörte Entfernung von topMostViewController.view die wieder in ihre ursprüngliche Position gebracht werden muss.

Schritt7:- I wiederhergestellt topMostViewController.view.frame nach unten entsprechend der gestörten Entfernung.

Schritt8:- Ich instanzierte singleton IQKeyboardManager Klasseninstanz beim Laden der Anwendung, so dass jede UITextField / UITextView in der App wird automatisch an die zu erwartende Entfernung angepasst.

Das ist alles IQKeyboardManager für Sie tun mit KEINE CODEZEILE Sie müssen nur die entsprechende Quelldatei in das Projekt ziehen und ablegen. IQKeyboardManager unterstützen auch Geräteausrichtung , Automatische UIToolbar-Verwaltung , KeybkeyboardDistanceFromTextField und viel mehr, als Sie denken.

0 Stimmen

Fügen Sie das Verzeichnis IQKeyBoardManagerSwift zu meinem Projekt hinzu und es funktioniert nicht. Kann nicht aktivieren cuz seine nicht erkennen in AppDelegate...

2 Stimmen

Das fühlt sich wie Phishing an, denn die eigentliche Lösung wird nicht gezeigt, stattdessen sehen wir eine Werbung für das GitHub-Konto dieses Mannes.

102voto

Michael Tyson Punkte 1468

Ich habe eine universelle, sofort einsetzbare UIScrollView , UITableView und sogar UICollectionView Unterklasse, die sich darum kümmert, dass alle darin enthaltenen Textfelder aus dem Weg der Tastatur verschoben werden.

Wenn die Tastatur erscheint, findet die Unterklasse die Unteransicht, die bearbeitet werden soll, und passt den Rahmen und den Inhaltsversatz an, um sicherzustellen, dass diese Ansicht sichtbar ist, mit einer Animation, die dem Pop-up der Tastatur entspricht. Wenn die Tastatur verschwindet, stellt sie ihre vorherige Größe wieder her.

Es sollte im Grunde mit jedem Setup funktionieren, entweder einem UITableView -basierten Schnittstelle oder einer aus manuell platzierten Ansichten bestehenden Schnittstelle.

Hier ist es: Lösung für das Verschieben von Textfeldern aus dem Weg der Tastatur

0 Stimmen

Das ist es! Dies ist die beste, effizienteste und perfekte Lösung! Auch bei Scroll-Ansichten werden Drehungen korrekt verarbeitet. Wenn Sie drehen, stellen Sie sicher, dass Sie die Größe vertikal anpassen, aber verankern Sie nicht am unteren Rand. In meinem Fall habe ich eine UITextView zur Bildlaufansicht hinzugefügt. Vielen Dank!

0 Stimmen

Sehr gute Arbeit! Sicher, ich bin faul mit Ihrer Lösung statt der DIY ein, aber mein Chef ist glücklicher, so yeah! Auch wenn jemand selbst machen will, gefällt mir dein Ansatz mit den Unterklassen, anstatt Code zu jedem Controller hinzuzufügen. Ich war schockiert iOS nicht tun dies standardmäßig wie Android tat - dann wieder, ich finde eine Menge Dinge in iOS und MacOS fehlt :(

0 Stimmen

Macht seltsame Dinge, wie z.B. dass meine Bildlaufansicht komplett in den Bildschirm passt, so dass sie nicht gescrollt werden kann. Nach dem Öffnen und Schließen der Tastatur ist der Inhalt jetzt größer (sieht aus, als ob etwas Unsichtbares am unteren Rand der Seite hinzugefügt und nicht entfernt wurde) und kann gescrollt werden.

94voto

Codetard Punkte 2214

Für Schnell Programmierer :

Dies wird alles für Sie tun, fügen Sie diese einfach in Ihre View-Controller-Klasse ein und implementieren Sie die UITextFieldDelegate zu Ihrem View-Controller und setzen Sie den Delegaten des textFields auf self

textField.delegate = self // Setting delegate of your UITextField to self

Implementieren Sie die Rückrufmethoden des Delegaten:

func textFieldDidBeginEditing(textField: UITextField) {
    animateViewMoving(true, moveValue: 100)
}

func textFieldDidEndEditing(textField: UITextField) {
    animateViewMoving(false, moveValue: 100)
}

// Lifting the view up
func animateViewMoving (up:Bool, moveValue :CGFloat){
    let movementDuration:NSTimeInterval = 0.3
    let movement:CGFloat = ( up ? -moveValue : moveValue)
    UIView.beginAnimations( "animateView", context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(movementDuration )
    self.view.frame = CGRectOffset(self.view.frame, 0,  movement)
    UIView.commitAnimations()
}

Für Swift 4, 4.2, 5: Ändern Sie

self.view.frame = CGRectOffset(self.view.frame, 0,  movement)

zu

self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)

Ein letzter Hinweis zu dieser Implementierung: Wenn Sie einen anderen View-Controller auf den Stapel schieben, während die Tastatur angezeigt wird, führt dies zu einem Fehler, bei dem die Ansicht in ihren mittleren Frame zurückgesetzt wird, aber der Tastatur-Offset nicht zurückgesetzt wird. Zum Beispiel ist Ihre Tastatur der erste Responder für nameField, aber dann drücken Sie eine Taste, die Ihren Hilfe-View-Controller auf Ihren Stapel schiebt. Um den Offset-Fehler zu beheben, stellen Sie sicher, dass Sie nameField.resignFirstResponder() aufrufen, bevor Sie den View Controller verlassen, und stellen Sie sicher, dass die Delegatenmethode textFieldDidEndEditing ebenfalls aufgerufen wird. Ich tue dies in der viewWillDisappear-Methode.

3 Stimmen

SwiftLint mochte nicht self.view.frame = CGRectOffset(self.view.frame, 0, movement) also habe ich diese Zeile geändert in self.view.frame.offsetInPlace(dx: 0, dy: movement)

2 Stimmen

Swift 4 change self.view.frame = CGRectOffset(self.view.frame, 0, movement) to self.view.frame.offsetBy(dx: 0, dy: movement)

0 Stimmen

FYI, für diese zu arbeiten, müssen Sie setzen. self.view.frame = self.view.frame.offsetBy(dx: 0, dy: Bewegung)

67voto

Martin Ullrich Punkte 85870

Es gibt bereits viele Antworten, aber noch keine der obigen Lösungen hatte all das ausgefallene Positionierungszeug, das für eine "perfekte" fehlerfreie, abwärtskompatible und flimmerfreie Animation erforderlich ist. (Fehler bei der Animation von frame/bounds und contentOffset zusammen, unterschiedliche Ausrichtungen der Oberfläche, iPad geteilte Tastatur, ...)
Lassen Sie mich meine Lösung mitteilen:
(vorausgesetzt, Sie haben die UIKeyboardWill(Show|Hide)Notification )

// Called when UIKeyboardWillShowNotification is sent
- (void)keyboardWillShow:(NSNotification*)notification
{
    // if we have no view or are not visible in any window, we don't care
    if (!self.isViewLoaded || !self.view.window) {
        return;
    }

    NSDictionary *userInfo = [notification userInfo];

    CGRect keyboardFrameInWindow;
    [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrameInWindow];

    // the keyboard frame is specified in window-level coordinates. this calculates the frame as if it were a subview of our view, making it a sibling of the scroll view
    CGRect keyboardFrameInView = [self.view convertRect:keyboardFrameInWindow fromView:nil];

    CGRect scrollViewKeyboardIntersection = CGRectIntersection(_scrollView.frame, keyboardFrameInView);
    UIEdgeInsets newContentInsets = UIEdgeInsetsMake(0, 0, scrollViewKeyboardIntersection.size.height, 0);

    // this is an old animation method, but the only one that retains compaitiblity between parameters (duration, curve) and the values contained in the userInfo-Dictionary.
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];

    _scrollView.contentInset = newContentInsets;
    _scrollView.scrollIndicatorInsets = newContentInsets;

    /*
     * Depending on visual layout, _focusedControl should either be the input field (UITextField,..) or another element
     * that should be visible, e.g. a purchase button below an amount text field
     * it makes sense to set _focusedControl in delegates like -textFieldShouldBeginEditing: if you have multiple input fields
     */
    if (_focusedControl) {
        CGRect controlFrameInScrollView = [_scrollView convertRect:_focusedControl.bounds fromView:_focusedControl]; // if the control is a deep in the hierarchy below the scroll view, this will calculate the frame as if it were a direct subview
        controlFrameInScrollView = CGRectInset(controlFrameInScrollView, 0, -10); // replace 10 with any nice visual offset between control and keyboard or control and top of the scroll view.

        CGFloat controlVisualOffsetToTopOfScrollview = controlFrameInScrollView.origin.y - _scrollView.contentOffset.y;
        CGFloat controlVisualBottom = controlVisualOffsetToTopOfScrollview + controlFrameInScrollView.size.height;

        // this is the visible part of the scroll view that is not hidden by the keyboard
        CGFloat scrollViewVisibleHeight = _scrollView.frame.size.height - scrollViewKeyboardIntersection.size.height;

        if (controlVisualBottom > scrollViewVisibleHeight) { // check if the keyboard will hide the control in question
            // scroll up until the control is in place
            CGPoint newContentOffset = _scrollView.contentOffset;
            newContentOffset.y += (controlVisualBottom - scrollViewVisibleHeight);

            // make sure we don't set an impossible offset caused by the "nice visual offset"
            // if a control is at the bottom of the scroll view, it will end up just above the keyboard to eliminate scrolling inconsistencies
            newContentOffset.y = MIN(newContentOffset.y, _scrollView.contentSize.height - scrollViewVisibleHeight);

            [_scrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
        } else if (controlFrameInScrollView.origin.y < _scrollView.contentOffset.y) {
            // if the control is not fully visible, make it so (useful if the user taps on a partially visible input field
            CGPoint newContentOffset = _scrollView.contentOffset;
            newContentOffset.y = controlFrameInScrollView.origin.y;

            [_scrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
        }
    }

    [UIView commitAnimations];
}

// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillHide:(NSNotification*)notification
{
    // if we have no view or are not visible in any window, we don't care
    if (!self.isViewLoaded || !self.view.window) {
        return;
    }

    NSDictionary *userInfo = notification.userInfo;

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[[userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[[userInfo valueForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];

    // undo all that keyboardWillShow-magic
    // the scroll view will adjust its contentOffset apropriately
    _scrollView.contentInset = UIEdgeInsetsZero;
    _scrollView.scrollIndicatorInsets = UIEdgeInsetsZero;

    [UIView commitAnimations];
}

0 Stimmen

Großartige Verbesserungen der Antwort von @Shiun. Aber nachdem die Tastatur weg ist, geht die Ansicht nicht zurück in die 1. Position. Es ist immer noch eine tolle Arbeit :)

2 Stimmen

Danke, das ist die beste Lösung für mich im Jahr 2017. Beachten Sie, dass Sie das focusedControl nicht selbst verfolgen müssen, Sie können es mit UIApplication.shared.sendAction(...) . Hier ist die Swift 3-Version Ihrer Antwort (ohne den willHide-Teil), mit dem sendAction umgesetzt: gist.github.com/xaphod/7aab1302004f6e933593a11ad8f5a72d

0 Stimmen

@xaphod in meinem Fall brauchte ich, um mehr Kontrollen zu konzentrieren - z.B. eine Schaltfläche unter einem Eingabefeld. aber ja, dass Code ist jetzt 4 Jahre alt und kann von Verbesserungen profitieren.

64voto

cbranch Punkte 4529

Shiun sagte: "Wie sich herausstellte, glaube ich, dass die UIScrollView tatsächlich implizit das aktuell bearbeitete UITextField in das sichtbare Fenster bringt" Dies scheint für iOS 3.1.3, aber nicht 3.2, 4.0 oder 4.1 wahr zu sein. Ich musste ein explizites scrollRectToVisible hinzufügen, um das UITextField auf iOS >= 3.2 sichtbar zu machen.

0 Stimmen

Es ist nicht die UIScrollView, die implizit das bearbeitete UITextField in die Ansicht scrollt, sondern das UITextField, das eine private [UITextField scrollTextFieldToVisibleIfNecessary] Methode, die ihrerseits die [UIScrollView scrollRectToVisible] cuando [UITextField becomeFirstResponder] genannt wird. Siehe github.com/leopatras/ios_textfields_on_scrollview . Wenn Constraints und View-Controller richtig eingerichtet sind, ist es eigentlich nicht nötig, die scrollRectToVisible ausdrücklich (zumindest seit IOS 11).

0 Stimmen

Ist so etwas möglich mit UITextView oder sollten wir das manuell behandeln?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X