it-swarm.com.de

Wie scrolle ich die UIScrollView, wenn die Tastatur angezeigt wird?

Ich habe Probleme mit meinem Code. Ich versuche die UIScrollView zu verschieben, wenn ich eine UITextField bearbeite, die durch den Popup der Tastatur ausgeblendet werden soll.

Ich bewege das Hauptframe jetzt, weil ich nicht weiß, wie ich im Code nach oben scrollen soll ..__ Also habe ich ein bisschen Code gemacht, es funktioniert gut, aber wenn ich ein UI-Textfeld bearbeite, wechsle ich zu einer anderen UITextField ohne auf die 'Zurück'-Schaltfläche zu drücken, geht die Hauptansicht waaayyyyy zu weit nach oben.

Ich habe eine NSLog() mit meinen Variablen size, distance und textFieldRect.Origin.y gemacht, wie Sie unten sehen können. Wenn ich zwei UITextField an derselben Stelle (y Origin) setze und diese bestimmte "Umschaltung" (ohne Drücken der Eingabetaste) mache, bekomme ich dieselben Zahlen, während mein Code gut für die erste UITextField-Bearbeitung funktionierte, nicht aber für die zweite Bearbeitung.

Überprüfen Sie dies heraus:

- (void)textFieldDidBeginEditing:(UITextField *)textField {
{
    int size;
    CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField];
    size = textFieldRect.Origin.y + textFieldRect.size.height;
    if (change == FALSE)
    {
        size = size - distance;
    }
    if (size < PORTRAIT_KEYBOARD_HEIGHT)
    {
        distance = 0;
    }
    else if (size > PORTRAIT_KEYBOARD_HEIGHT)
    {
        distance = size - PORTRAIT_KEYBOARD_HEIGHT + 5; // +5 px for more visibility
    }
    NSLog(@"Origin %f", textFieldRect.Origin.y);
    NSLog(@"size %d", size);
    NSLog(@"distance %d", distance);
    CGRect viewFrame = self.view.frame;
    viewFrame.Origin.y -= distance;
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
    [self.view setFrame:viewFrame];
    [UIView commitAnimations];
    change = FALSE;
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
    change = TRUE;
    CGRect viewFrame = self.view.frame;
    viewFrame.Origin.y += distance;
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
    [self.view setFrame:viewFrame];
    [UIView commitAnimations];
}

Irgendwelche Ideen ?

87
frénésie

Die empfohlene Methode von Apple besteht darin, die contentInset der UIScrollView zu ändern. Es ist eine sehr elegante Lösung, da Sie sich nicht mit der contentSize herumschlagen müssen. Der folgende Code wurde aus dem Keyboard Programming Guide kopiert, in dem die Behandlung dieses Problems erläutert wird. Sie sollten einen Blick darauf werfen.

// Call this method somewhere in your view controller setup code.
- (void)registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
            selector:@selector(keyboardWasShown:)
            name:UIKeyboardDidShowNotification object:nil];
   [[NSNotificationCenter defaultCenter] addObserver:self
             selector:@selector(keyboardWillBeHidden:)
             name:UIKeyboardWillHideNotification object:nil];
}

// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
    scrollView.contentInset = contentInsets;
    scrollView.scrollIndicatorInsets = contentInsets;

    // If active text field is hidden by keyboard, scroll it so it's visible
    // Your application might not need or want this behavior.
    CGRect aRect = self.view.frame;
    aRect.size.height -= kbSize.height;
    if (!CGRectContainsPoint(aRect, activeField.frame.Origin) ) {
        CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.Origin.y-kbSize.height);
        [scrollView setContentOffset:scrollPoint animated:YES];
    }
}

// Called when the UIKeyboardWillHideNotification is sent    
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    scrollView.contentInset = contentInsets;
    scrollView.scrollIndicatorInsets = contentInsets;
}

Swift-Version:

func registerForKeyboardNotifications() {
    NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardAppear(_:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardDisappear(_:)), name: NSNotification.Name.UIKeyboardDidHide, object: nil)
}

// Don't forget to unregister when done
deinit {
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidShow, object: nil)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidHide, object: nil)
}

@objc func onKeyboardAppear(_ notification: NSNotification) {
    let info = notification.userInfo!
    let rect: CGRect = info[UIKeyboardFrameBeginUserInfoKey] as! CGRect
    let kbSize = rect.size

    let insets = UIEdgeInsetsMake(0, 0, kbSize.height, 0)
    scrollView.contentInset = insets
    scrollView.scrollIndicatorInsets = insets

    // If active text field is hidden by keyboard, scroll it so it's visible
    // Your application might not need or want this behavior.
    var aRect = self.view.frame;
    aRect.size.height -= kbSize.height;

    let activeField: UITextField? = [addressTextView, servicePathTextView, usernameTextView, passwordTextView].first { $0.isFirstResponder }
    if let activeField = activeField {
        if aRect.contains(activeField.frame.Origin) {
            let scrollPoint = CGPoint(x: 0, y: activeField.frame.Origin.y-kbSize.height)
            scrollView.setContentOffset(scrollPoint, animated: true)
        }
    }
}

@objc func onKeyboardDisappear(_ notification: NSNotification) {
    scrollView.contentInset = UIEdgeInsets.zero
    scrollView.scrollIndicatorInsets = UIEdgeInsets.zero
}
182
Masa

Ich habe dies gerade mit Swift 2.0 für iOS9 auf Xcode 7 (Beta 6) implementiert, funktioniert hier gut.

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    registerKeyboardNotifications()
}

func registerKeyboardNotifications() {
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
}

deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

func keyboardWillShow(notification: NSNotification) {
    let userInfo: NSDictionary = notification.userInfo!
    let keyboardSize = userInfo.objectForKey(UIKeyboardFrameBeginUserInfoKey)!.CGRectValue.size
    let contentInsets = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0)
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets

    var viewRect = view.frame
    viewRect.size.height -= keyboardSize.height
    if CGRectContainsPoint(viewRect, textField.frame.Origin) {
        let scrollPoint = CGPointMake(0, textField.frame.Origin.y - keyboardSize.height)
        scrollView.setContentOffset(scrollPoint, animated: true)
    }
}

func keyboardWillHide(notification: NSNotification) {
    scrollView.contentInset = UIEdgeInsetsZero
    scrollView.scrollIndicatorInsets = UIEdgeInsetsZero
}

Für Swift 3 bearbeitet

Anscheinend müssen Sie nur die Variable contentInset und scrollIndicatorInset mit Swift 3 einstellen.

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    registerKeyboardNotifications()
}

func registerKeyboardNotifications() {
    NotificationCenter.default.addObserver(self,
                                         selector: #selector(keyboardWillShow(notification:)),
                                         name: NSNotification.Name.UIKeyboardWillShow,
                                         object: nil)
    NotificationCenter.default.addObserver(self,
                                         selector: #selector(keyboardWillHide(notification:)),
                                         name: NSNotification.Name.UIKeyboardWillHide,
                                         object: nil)
}

deinit {
    NotificationCenter.default.removeObserver(self)
}

func keyboardWillShow(notification: NSNotification) {
    let userInfo: NSDictionary = notification.userInfo! as NSDictionary
    let keyboardInfo = userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue
    let keyboardSize = keyboardInfo.cgRectValue.size
    let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets
}

func keyboardWillHide(notification: NSNotification) {
    scrollView.contentInset = .zero
    scrollView.scrollIndicatorInsets = .zero
}
62
Johannes

Alle Antworten scheinen die landschaftlichen Möglichkeiten zu vergessen. Wenn Sie möchten, dass dies funktioniert, wenn das Gerät in eine Querformatansicht gedreht wird, treten Probleme auf.

Der Trick hier ist, dass, obwohl die Ansicht die Ausrichtung kennt, die Tastatur dies nicht tut. Dies bedeutet in Landscape, dass die Breite der Tastatur tatsächlich die Höhe ist und umgekehrt.

Wenn Sie die von Apples empfohlene Methode zum Ändern der Inhaltsinsets und zur Unterstützung der Querformatausrichtung ändern möchten, würde ich Folgendes empfehlen:

// Call this method somewhere in your view controller setup code.
- (void)registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
            selector:@selector(keyboardWasShown:)
            name:UIKeyboardDidShowNotification object:nil];
   [[NSNotificationCenter defaultCenter] addObserver:self
             selector:@selector(keyboardWillBeHidden:)
             name:UIKeyboardWillHideNotification object:nil];
}

// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    CGSize keyboardSize = [[[notif userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    if (orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight ) {
        CGSize origKeySize = keyboardSize;
        keyboardSize.height = origKeySize.width;
        keyboardSize.width = origKeySize.height;
    }
    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0);
    scroller.contentInset = contentInsets;
    scroller.scrollIndicatorInsets = contentInsets;

    // If active text field is hidden by keyboard, scroll it so it's visible
    // Your application might not need or want this behavior.
    CGRect rect = scroller.frame;
    rect.size.height -= keyboardSize.height;
    NSLog(@"Rect Size Height: %f", rect.size.height);

    if (!CGRectContainsPoint(rect, activeField.frame.Origin)) {
        CGPoint point = CGPointMake(0, activeField.frame.Origin.y - keyboardSize.height);
        NSLog(@"Point Height: %f", point.y);
        [scroller setContentOffset:point animated:YES];
    }
}

// Called when the UIKeyboardWillHideNotification is sent    
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    scrollView.contentInset = contentInsets;
    scrollView.scrollIndicatorInsets = contentInsets;
}

Der hier zu beachtende Teil ist folgender:

UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
CGSize keyboardSize = [[[notif userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
if (orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight ) {
    CGSize origKeySize = keyboardSize;
    keyboardSize.height = origKeySize.width;
    keyboardSize.width = origKeySize.height;
}

Was bedeutet, erkennt, in welcher Ausrichtung sich das Gerät befindet. Wenn es sich um ein Querformat handelt, werden die Werte für Breite und Höhe der keyboardSize-Variablen "ausgetauscht", um sicherzustellen, dass in jeder Ausrichtung die richtigen Werte verwendet werden.

15
Rob

Für dieses Zeug ist es nicht nötig, jede Menge Codierung zu machen, es ist sehr einfach wie unter dem folgenden Code: -

ihr aller Text in UIScrollview von Feder wie dieses Bild: -

enter image description here

YourViewController.h

@interface cntrInquiryViewController : UIViewController<UIScrollViewDelegate,UITextFieldDelegate>
{
     IBOutlet UITextField *txtName;
     IBOutlet UITextField *txtEmail;
     IBOutlet UIScrollView *srcScrollView;
}
@end

IBOutlet von der Spitze her verbinden und jeden Delegierten von UItextfiled und Scrollview-Delegaten von der NIB verbinden

-(void)viewWillAppear:(BOOL)animated
{
    srcScrollView.contentSize = CGSizeMake(320, 500);

    [super viewWillAppear:YES];
}


-(void)textFieldDidBeginEditing:(FMTextField *)textField
{
    [srcScrollView setContentOffset:CGPointMake(0,textField.center.y-140) animated:YES];//you can set your  y cordinate as your req also
}

-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
     [textField resignFirstResponder];
     [srcScrollView setContentOffset:CGPointMake(0,0) animated:YES];


    return YES;
}

NOTEWenn der Delegierte mit Text nicht verbunden ist, kann keine Methode funktionieren. Stellen Sie sicher, dass alle iBOulate und Delegierten korrekt verbunden sind 

9
Nitin Gohel

Swift 4 Lösung:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    registerKeyboardNotifications()
}

func registerKeyboardNotifications() {
    NotificationCenter.default.addObserver(self,
                                         selector: #selector(keyboardWillShow(notification:)),
                                         name: NSNotification.Name.UIKeyboardWillShow,
                                         object: nil)
    NotificationCenter.default.addObserver(self,
                                         selector: #selector(keyboardWillHide(notification:)),
                                         name: NSNotification.Name.UIKeyboardWillHide,
                                         object: nil)
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    NotificationCenter.default.removeObserver(self)
}

@objc func keyboardWillShow(notification: NSNotification) {
    let userInfo: NSDictionary = notification.userInfo! as NSDictionary
    let keyboardInfo = userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue
    let keyboardSize = keyboardInfo.cgRectValue.size
    let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets
}

@objc func keyboardWillHide(notification: NSNotification) {
    scrollView.contentInset = .zero
    scrollView.scrollIndicatorInsets = .zero
}
8
user7718859

Apples Empfehlung neu codiert in Swift + Verwenden von UIScrollView mit Auto Layout in iOS (basierend auf den folgenden Links: Link 1 , Link 2 , Link 3 ):

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet var t1: UITextField!
    @IBOutlet var t2: UITextField!
    @IBOutlet var t3: UITextField!
    @IBOutlet var t4: UITextField!

    @IBOutlet var srcScrollView: UIScrollView!

    @IBOutlet var contentView: UIView!

    var contentViewCoordinates: CGPoint!

    override func viewDidLoad() {

        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        /* Constraints on content view */
        let leftConstraint = NSLayoutConstraint(item:self.contentView,
            attribute:NSLayoutAttribute.Leading,
            relatedBy:NSLayoutRelation.Equal,
            toItem:self.view,
            attribute:NSLayoutAttribute.Left,
            multiplier:1.0,
            constant:0)
        self.view.addConstraint(leftConstraint)

        let rightConstraint = NSLayoutConstraint(item:self.contentView,
            attribute:NSLayoutAttribute.Trailing,
            relatedBy:NSLayoutRelation.Equal,
            toItem:self.view,
            attribute:NSLayoutAttribute.Right,
            multiplier:1.0,
            constant:0)
        self.view.addConstraint(rightConstraint)

        /* Tap gesture */
        let tapGesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "hideKeyboard")
        // prevents the scroll view from swallowing up the touch event of child buttons
        tapGesture.cancelsTouchesInView = false
        srcScrollView.addGestureRecognizer(tapGesture)

        /* Save content view coordinates */
        contentViewCoordinates = contentView.frame.Origin
    }

    func hideKeyboard() {
        t1.resignFirstResponder()
        t2.resignFirstResponder()
        t3.resignFirstResponder()
        t4.resignFirstResponder()
    }

    var activeField: UITextField?

    func textFieldDidBeginEditing(textField: UITextField) {
        activeField = textField
    }

    func textFieldDidEndEditing(textField: UITextField) {
        activeField = nil
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        let center = NSNotificationCenter.defaultCenter()
        center.addObserver(self, selector: "keyboardOnScreen:", name: UIKeyboardDidShowNotification, object: nil)
        center.addObserver(self, selector: "keyboardOffScreen:", name: UIKeyboardDidHideNotification, object: nil)
    }

    func keyboardOnScreen(notification: NSNotification){
        // Retrieve the size and top margin (inset is the fancy Word used by Apple) 
        // of the keyboard displayed.
        let info: NSDictionary  = notification.userInfo!
        let kbSize = info.valueForKey(UIKeyboardFrameEndUserInfoKey)?.CGRectValue().size
        let contentInsets: UIEdgeInsets  = UIEdgeInsetsMake(0.0, 0.0, kbSize!.height, 0.0)

        srcScrollView.contentInset = contentInsets
        srcScrollView.scrollIndicatorInsets = contentInsets

        var aRect: CGRect = self.view.frame
        aRect.size.height -= kbSize!.height
        //you may not need to scroll, see if the active field is already visible
        if (CGRectContainsPoint(aRect, activeField!.frame.Origin) == false) {
            let scrollPoint:CGPoint = CGPointMake(0.0, activeField!.frame.Origin.y - kbSize!.height)
            srcScrollView.setContentOffset(scrollPoint, animated: true)
        }
    }

//    func keyboardOnScreen(aNotification: NSNotification) {
//        let info: NSDictionary  = aNotification.userInfo!
//        let kbSize = info.valueForKey(UIKeyboardFrameEndUserInfoKey)?.CGRectValue().size
//        
//        var bkgndRect: CGRect! = activeField?.superview?.frame
//        
//        bkgndRect.size.height += kbSize!.height
//        
//        activeField?.superview?.frame = bkgndRect
//        
//        srcScrollView.setContentOffset(CGPointMake(0.0, activeField!.frame.Origin.y - kbSize!.height), animated: true)
//    }

    func keyboardOffScreen(notification: NSNotification){
        let contentInsets:UIEdgeInsets = UIEdgeInsetsZero

        srcScrollView.contentInset = contentInsets
        srcScrollView.scrollIndicatorInsets = contentInsets

        self.srcScrollView.setContentOffset(CGPointMake(0, -self.view.frame.Origin.y/2), animated: true)
    }

}
7
King-Wizard

Das einzige, was ich in Apple-Code aktualisieren würde, ist die keyboardWillBeHidden: -Methode, um einen reibungslosen Übergang zu ermöglichen.

// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;

    [UIView animateWithDuration:0.4 animations:^{
        self.scrollView.contentInset = contentInsets;
    }];
    self.scrollView.scrollIndicatorInsets = contentInsets;

}
4
Jovan Stankovic

Hier ist eine Swift 3 kompatible Antwort, die auch mit Ansichtscontrollern innerhalb eines Navigationscontrollers funktioniert - da sie die Scroll-Eigenschaften contentInset.top ändern.

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    self.registerKeyboardNotifications()
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    self.unregisterKeyboardNotifications()
}

func registerKeyboardNotifications() {
    NotificationCenter.default.addObserver(self, selector: #selector(LoginViewController.keyboardDidShow(notification:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(LoginViewController.keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

func unregisterKeyboardNotifications() {
    NotificationCenter.default.removeObserver(self)
}


func keyboardDidShow(notification: NSNotification) {
    let userInfo: NSDictionary = notification.userInfo! as NSDictionary
    let keyboardInfo = userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue
    let keyboardSize = keyboardInfo.cgRectValue.size

    // Get the existing contentInset for the scrollView and set the bottom property to be the height of the keyboard
    var contentInset = self.scrollView.contentInset
    contentInset.bottom = keyboardSize.height

    self.scrollView.contentInset = contentInset
    self.scrollView.scrollIndicatorInsets = contentInset
}

func keyboardWillHide(notification: NSNotification) {
    var contentInset = self.scrollView.contentInset
    contentInset.bottom = 0

    self.scrollView.contentInset = contentInset
    self.scrollView.scrollIndicatorInsets = UIEdgeInsets.zero
}
4
rdougan

Ich habe festgestellt, dass die obigen Antworten veraltet sind. Auch beim Blättern nicht perfekt.

Hier ist eine schnelle Version. 

Es wird direkt unter dem Textfeld angezeigt, kein freier Speicherplatz. Und es wird so wiederhergestellt, wie es beim ersten Erscheinen war.

//add observer
override func viewDidLoad() {
    super.viewDidLoad()

    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ARVHttpPlayVC.keyboardDidShow(_:)), name: UIKeyboardDidShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ARVHttpPlayVC.keyboardDidHide(_:)), name: UIKeyboardDidHideNotification, object: nil)
}

func keyboardDidShow(notification: NSNotification) {
    let userInfo: NSDictionary = notification.userInfo!
    let keyboardSize = userInfo.objectForKey(UIKeyboardFrameEndUserInfoKey)!.CGRectValue.size
    let difference = keyboardSize.height - (self.view.frame.height - inputTextField.frame.Origin.y - inputTextField.frame.size.height)
    if difference > 0 {
        var contentInset:UIEdgeInsets = self.scrollView.contentInset
        contentInset.bottom = difference
        self.scrollView.contentInset = contentInset

        let scrollPoint = CGPointMake(0, difference)
        self.scrollView.setContentOffset(scrollPoint, animated: true)
    }

}

func keyboardDidHide(notification: NSNotification) {
    let contentInset:UIEdgeInsets = UIEdgeInsetsZero
    self.scrollView.contentInset = contentInset
}

//remove observer
deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}
3
ronan

Versuchen Sie diesen Code in Swift 3:

override func viewDidAppear(_ animated: Bool) {
    setupViewResizerOnKeyboardShown()
}

func setupViewResizerOnKeyboardShown() {
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(self.keyboardWillShowForResizing),
                                           name: Notification.Name.UIKeyboardWillShow,
                                           object: nil)
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(self.keyboardWillHideForResizing),
                                           name: Notification.Name.UIKeyboardWillHide,
                                           object: nil)
}

func keyboardWillShowForResizing(notification: Notification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
        let window = self.view.window?.frame {
        // We're not just minusing the kb height from the view height because
        // the view could already have been resized for the keyboard before
        self.view.frame = CGRect(x: self.view.frame.Origin.x,
                                 y: self.view.frame.Origin.y,
                                 width: self.view.frame.width,
                                 height: window.Origin.y + window.height - keyboardSize.height)

    } else {
        debugPrint("We're showing the keyboard and either the keyboard size or window is nil: panic widely.")
    }
}

func keyboardWillHideForResizing(notification: Notification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        let viewHeight = self.view.frame.height
        self.view.frame = CGRect(x: self.view.frame.Origin.x,
                                 y: self.view.frame.Origin.y,
                                 width: self.view.frame.width,
                                 height: viewHeight) //viewHeight + keyboardSize.height

    } else {
        debugPrint("We're about to hide the keyboard and the keyboard size is nil. Now is the rapture.")
    }
}

deinit {
        NotificationCenter.default.removeObserver(self)
    }
2
Naveen Kumar M

Das habe ich benutzt. Es ist einfach und funktioniert gut. 

#pragma mark - Scrolling

-(void)scrollElement:(UIView *)view toPoint:(float)y
{
    CGRect theFrame = view.frame;
    float orig_y = theFrame.Origin.y;
    float diff = y - orig_y;

    if (diff < 0) 
        [self scrollToY:diff];

    else 
        [self scrollToY:0];
}

-(void)scrollToY:(float)y
{
    [UIView animateWithDuration:0.3f animations:^{
        [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
        self.view.transform = CGAffineTransformMakeTranslation(0, y);
    }];
}

Verwenden Sie den Delegate-Aufruf UITextFieldtextFieldDidBeginEditing:, um die Ansicht nach oben zu verschieben, und fügen Sie einen Benachrichtigungsbeobachter hinzu, um die Ansicht wieder normal anzuzeigen, wenn die Tastatur ausgeblendet wird:

-(void)textFieldDidBeginEditing:(UITextField *)textField
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];

    if (self.view.frame.Origin.y == 0)
        [self scrollToY:-90.0];  // y can be changed to your liking

}

-(void)keyboardWillHide:(NSNotification*)note
{
    [self scrollToY:0];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
2
Anthony

Dies ist der endgültige Code mit Verbesserungen in Swift

    //MARK: UITextFieldDelegate
func textFieldDidBeginEditing(textField: UITextField!) {    //delegate method
    self.textField = textField
}

func textFieldShouldReturn(textField: UITextField!) -> Bool {   //delegate method
    textField.resignFirstResponder()
    return true
}

//MARK: Keyboard handling
override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)
    unregisterKeyboardNotifications()
}

func registerKeyboardNotifications() {
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UCProfileSettingsViewController.keyboardDidShow(_:)), name: UIKeyboardDidShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UCProfileSettingsViewController.keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil)
}

func unregisterKeyboardNotifications() {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

func keyboardDidShow(notification: NSNotification) {
    let userInfo: NSDictionary = notification.userInfo!
    let keyboardSize = userInfo.objectForKey(UIKeyboardFrameBeginUserInfoKey)!.CGRectValue.size
    let contentInsets = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0)
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets

    var viewRect = self.view.frame
    viewRect.size.height -= keyboardSize.height
    let relativeFieldFrame: CGRect = textField.convertRect(textField.frame, toView: self.view)
    if CGRectContainsPoint(viewRect, relativeFieldFrame.Origin) {
        let scrollPoint = CGPointMake(0, relativeFieldFrame.Origin.y - keyboardSize.height)
        scrollView.setContentOffset(scrollPoint, animated: true)
    }

}

func keyboardWillHide(notification: NSNotification) {
    scrollView.contentInset = UIEdgeInsetsZero
    scrollView.scrollIndicatorInsets = UIEdgeInsetsZero
}
2

Das würde ich so machen. Es ist viel Code, aber es stellt sicher, dass das aktuell im Fokus befindliche textField vertikal im verfügbaren Bereich zentriert ist:

- (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 {
    NSDictionary *info = [notification userInfo];
    NSValue *keyBoardEndFrame = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
    CGSize keyboardSize = [keyBoardEndFrame CGRectValue].size;
    self.keyboardSize = keyboardSize;

    [self adjustScrollViewOffsetToCenterTextField:self.currentTextField];
}

- (void)keyboardWillHide:(NSNotification *)notification {
    self.keyboardSize = CGSizeZero;
}

- (IBAction)textFieldGotFocus:(UITextField *)sender {
    sender.inputAccessoryView = self.keyboardAccessoryView;
    self.currentTextField = sender;
    [self adjustScrollViewOffsetToCenterTextField:sender];    
}

- (void)adjustScrollViewOffsetToCenterTextField:(UITextField *)textField
{
    CGRect textFieldFrame = textField.frame;
    float keyboardHeight = MIN(self.keyboardSize.width, self.keyboardSize.height);

    float visibleScrollViewHeight = self.scrollView.frame.size.height - keyboardHeight;
    float offsetInScrollViewCoords = (visibleScrollViewHeight / 2) - (textFieldFrame.size.height / 2);

    float scrollViewOffset = textFieldFrame.Origin.y - offsetInScrollViewCoords;


    [UIView animateWithDuration:.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
        self.scrollView.contentOffset = CGPointMake(self.scrollView.contentOffset.x, scrollViewOffset);
    }completion:NULL];

}

you'll need these two properties in your @interface...
@property (nonatomic, assign) CGSize keyboardSize;
@property (nonatomic, strong) UITextField *currentTextField;

Beachten Sie, dass die - (IBAction)textFieldGotFocus:-Aktion mit dem DidBeginEditing-Zustand jedes textField verbunden ist.

Es wäre auch ein bisschen besser, die Animationsdauer aus der Tastaturbenachrichtigung herauszuholen und diese für die ScrollView-Animation anstelle eines festen Werts zu verwenden.

1
Tobi

Verwenden Sie die folgende Erweiterung, wenn Sie nicht zu viel berechnen möchten:

func scrollSubviewToBeVisible(subview: UIView, animated: Bool) {
    let visibleFrame = UIEdgeInsetsInsetRect(self.bounds, self.contentInset)
    let subviewFrame = subview.convertRect(subview.bounds, toView: self)
    if (!CGRectContainsRect(visibleFrame, subviewFrame)) {
        self.scrollRectToVisible(subviewFrame, animated: animated)
    }
}

Und vielleicht möchten Sie Ihr UITextField immer sichtbar lassen:

func textViewDidChange(textView: UITextView) {
    self.scrollView?.scrollSubviewToBeVisible(textView, animated: false)
}
0
CopperCash

Sie können einen Bildlauf durchführen, indem Sie die Eigenschaft contentOffset in UIScrollView verwenden, z.

CGPoint offset = scrollview.contentOffset;
offset.y -= KEYBOARD_HEIGHT + 5;
scrollview.contentOffset = offset;

Es gibt auch eine Methode zum animierten Scrollen.

Der Grund dafür, dass Ihre zweite Bearbeitung nicht korrekt gescrollt wird, kann daran liegen, dass Sie bei jedem Beginn der Bearbeitung von einer neuen Tastatur ausgehen. Sie könnten versuchen zu prüfen, ob Sie bereits die sichtbare Position der "Tastatur" eingestellt haben (und ebenfalls die Sichtbarkeit der Tastatur prüfen, bevor Sie sie zurücksetzen).

Eine bessere Lösung wäre das Abhören der Tastaturbenachrichtigung, z. B .:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardDidShow:)
                                             name:UIKeyboardDidShowNotification
                                           object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillHide:)
                                             name:UIKeyboardWillHideNotification
                                           object:nil];
0
Arkku

Ich weiß, es ist jetzt eine alte Frage, aber ich dachte, es könnte anderen helfen. Ich wollte, dass für ein paar Apps, die ich hatte, etwas einfacher zu implementieren ist, deshalb habe ich dafür eine Klasse gemacht. Sie können es hier herunterladen, wenn Sie möchten: https://github.com/sdernley/iOSTextFieldHandler

Es ist so einfach, alle UITextFields so einzustellen, dass sie einen eigenen Delegierten haben 

textfieldname.delegate = self;

Fügen Sie diese dann mit dem Namen Ihrer ScrollView- und Submit-Schaltfläche Ihrem View-Controller hinzu

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    [iOSTextFieldHandler TextboxKeyboardMover:containingScrollView tf:textField btn:btnSubmit];
}
0
sdernley

Meine Lösung hat 4 Schritte:
- Schritt 1: Die Funktion hört zu, wenn die Tastatur angezeigt wird

- (void)keyboardWasShown:(NSNotification *)notification {
// Get the size of the keyboard.
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
//top: 64 for navigation bar, 0 for without navigation
UIEdgeInsets contentInsets = UIEdgeInsetsMake(64, 0, keyboardSize.height, 0);
_scrollView.contentInset = contentInsets;
_scrollView.scrollIndicatorInsets = contentInsets;
}

- Schritt 2: Die Funktion hört zu, wenn die Tastatur ausgeblendet wird

- (void)keyboardWillHide:(NSNotification *)notification {
//top: 64 for navigatiob bar
UIEdgeInsets contentInsets = UIEdgeInsetsMake(64, 0, 0, 0);
[_editScrollView setContentInset: contentInsets];
[_editScrollView setScrollIndicatorInsets: contentInsets];
}

- Schritt 3: Fügen Sie diese Funktionen zur Benachrichtigungszentrale hinzu:

- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}

- Schritt 4: Entfernen der Überwachung, wenn der Ansichts-Controller verschwindet

- (void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
0

Swift 4.2 - Lösung, die mögliche Höhen von UIToolbar und UITabBar berücksichtigt. 

private func setupKeyboardNotifications() {
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIControl.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIControl.keyboardWillHideNotification, object: nil)
}

@objc func keyboardWillShow(_ notification: Notification) {
    let userInfo: NSDictionary = notification.userInfo! as NSDictionary
    let keyboardSize = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue.size

    let tabbarHeight = tabBarController?.tabBar.frame.size.height ?? 0
    let toolbarHeight = navigationController?.toolbar.frame.size.height ?? 0
    let bottomInset = keyboardSize.height - tabbarHeight - toolbarHeight

    scrollView.contentInset.bottom = bottomInset
    scrollView.scrollIndicatorInsets.bottom = bottomInset
}

@objc func keyboardWillHide(_ notification: Notification) {
    scrollView.contentInset = .zero
    scrollView.scrollIndicatorInsets = .zero
}

Wenn Sie auf <iOS 9 abzielen, müssen Sie den Beobachter zu einem bestimmten Zeitpunkt abmelden (danke Joe ).

0
JanApotheker

Dafür benötigen Sie eigentlich keine UIScrollView. Ich habe diesen Code verwendet und es funktioniert für mich:

-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{

   if (textField==_myTextField)
   {
      [self keyBoardAppeared];
   }
   return true;
}

-(void)textFieldDidEndEditing:(UITextField *)textField {
   if (textField==_myTextField)
   {
      [self keyBoardDisappeared];
   }
}

-(void) keyBoardAppeared
{
   CGRect frame = self.view.frame;

[UIView animateWithDuration:0.3
                      delay:0
                    options: UIViewAnimationCurveEaseOut
                 animations:^{
                     self.view.frame = CGRectMake(frame.Origin.x, frame.Origin.y-215, frame.size.width, frame.size.height);
                 }
                 completion:^(BOOL finished){

                 }];
}

-(void) keyBoardDisappeared
{
   CGRect frame = self.view.frame;

  [UIView animateWithDuration:0.3
                      delay:0
                    options: UIViewAnimationCurveEaseOut
                 animations:^{
                     self.view.frame = CGRectMake(frame.Origin.x, frame.Origin.y+215, frame.size.width, frame.size.height);
                 }
                 completion:^(BOOL finished){

                 }];
}
0
Timur Mustafaev

Eine der einfachsten Lösungen ist die Verwendung des folgenden Protokolls:

protocol ScrollViewKeyboardDelegate: class {
    var scrollView: UIScrollView? { get set }

    func registerKeyboardNotifications()
    func unregisterKeyboardNotifications()
}

extension ScrollViewKeyboardDelegate where Self: UIViewController {
    func registerKeyboardNotifications() {
        NotificationCenter.default.addObserver(
            forName: UIResponder.keyboardWillChangeFrameNotification,
            object: nil,
            queue: nil) { [weak self] notification in
                self?.keyboardWillBeShown(notification)
        }

        NotificationCenter.default.addObserver(
            forName: UIResponder.keyboardWillHideNotification,
            object: nil,
            queue: nil) { [weak self] notification in
                self?.keyboardWillBeHidden(notification)
        }
    }

    func unregisterKeyboardNotifications() {
        NotificationCenter.default.removeObserver(
            self,
            name: UIResponder.keyboardWillChangeFrameNotification,
            object: nil
        )
        NotificationCenter.default.removeObserver(
            self,
            name: UIResponder.keyboardWillHideNotification,
            object: nil
        )
    }

    func keyboardWillBeShown(_ notification: Notification) {
        let info = notification.userInfo
        let key = (info?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)
        let aKeyboardSize = key?.cgRectValue

        guard let keyboardSize = aKeyboardSize,
            let scrollView = self.scrollView else {
                return
        }

        let bottomInset = keyboardSize.height
        scrollView.contentInset.bottom = bottomInset
        scrollView.scrollIndicatorInsets.bottom = bottomInset
        if let activeField = self.view.firstResponder {
            let yPosition = activeField.frame.Origin.y - bottomInset
            if yPosition > 0 {
                let scrollPoint = CGPoint(x: 0, y: yPosition)
                scrollView.setContentOffset(scrollPoint, animated: true)
            }
        }
    }

    func keyboardWillBeHidden(_ notification: Notification) {
        self.scrollView?.contentInset = .zero
        self.scrollView?.scrollIndicatorInsets = .zero
    }
}

extension UIView {
    var firstResponder: UIView? {
        guard !isFirstResponder else { return self }
        return subviews.first(where: {$0.firstResponder != nil })
    }
}

Wenn Sie dieses Protokoll verwenden möchten, müssen Sie es nur wie folgt anpassen und Ihre Bildlaufansicht in Ihrem Controller zuweisen:

class MyViewController: UIViewController {
      @IBOutlet var scrollViewOutlet: UIScrollView?
      var scrollView: UIScrollView?

      public override func viewDidLoad() {
        super.viewDidLoad()

        self.scrollView = self.scrollViewOutlet
        self.scrollView?.isScrollEnabled = true
        self.registerKeyboardNotifications()
    }

    extension MyViewController: ScrollViewKeyboardDelegate {}

    deinit {
       self.unregisterKeyboardNotifications()
    }

}
0

Das Folgende ist meine Lösung, die funktioniert (5 Schritte) 

Schritt 1: Fügen Sie einen Beobachter hinzu, um das UITEXTFIELD- oder UITEXTVIEW ShoudBeginEditing-Objekt zu erfassen (wobei das Objekt inited oder ViewDidLoad ist).

[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(updateActiveField:)
                                             name:@"UPDATE_ACTIVE_FIELD" object:nil];

Schritt 2: Senden Sie eine Benachrichtigung, wenn ..ShouldBeginEditing mit OBJECT von UITEXTFIELD oder UITEXTVIEW 

-(BOOL)textViewShouldBeginEditing:(UITextView *)textView {

[[NSNotificationCenter defaultCenter] postNotificationName:@"UPDATE_ACTIVE_FIELD" 
                                                    object:textView];
return YES;
}

Schritt 3: Die Methode, die (Schritt 1) ​​aufgerufen wird, weist das aktuelle UITEXTFIELD oder UITEXTVIEW zu

-(void) updateActiveField: (id) sender {
    activeField = [sender object];
}

Schritt 4: Tastaturbeobachter UIKeyboardWillShowNotification hinzufügen (gleiche Stelle wie Schritt 1)

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWasShown:)
                                             name:UIKeyboardDidShowNotification object:nil];

und Methode:

// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);

    _currentEdgeInsets = self.layoutPanel.contentInset; // store current insets to restore them later
    self.layoutPanel.contentInset = contentInsets;
    self.layoutPanel.scrollIndicatorInsets = contentInsets;

    // If active text field is hidden by keyboard, scroll it so it's visible
    CGRect aRect =  self.view.frame;
    aRect.size.height -= kbSize.height;

    UIWindow *window = [[UIApplication sharedApplication] keyWindow];
    CGPoint p = [activeField convertPoint:activeField.bounds.Origin toView:window];

    if (!CGRectContainsPoint(aRect, p) ) {
        CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.Origin.y +kbSize.height);
       [self.layoutPanel setContentOffset:scrollPoint animated:YES];
       self.layoutPanel.scrollEnabled = NO;
    }
}

Schritt 5: Tastaturbeobachter UIKeyboardWillHideNotification hinzufügen (gleiche Stelle wie Schritt 1)

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillBeHidden:)
                                                 name:UIKeyboardWillHideNotification object:nil];

und Methode:

// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    self.layoutPanel.contentInset = _currentEdgeInsets;
    self.layoutPanel.scrollIndicatorInsets = _currentEdgeInsets;
    self.layoutPanel.scrollEnabled = YES;
}

Denken Sie daran, Beobachter zu entfernen!

0
Mike Zriel

Ich habe diese Antwort von Sudheer Palchuri verwendet https://stackoverflow.com/users/2873919/sudheer-palchurihttps://stackoverflow.com/a/32583809/6193496

Registrieren Sie die Benachrichtigungen in ViewDidLoad:

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(DetailsViewController.keyboardWillShow(_:)), name:UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(DetailsViewController.keyboardWillHide(_:)), name:UIKeyboardWillHideNotification, object: nil)

Fügen Sie unten Observer-Methoden hinzu, die das automatische Scrollen durchführen, wenn die Tastatur angezeigt wird.

func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}

func keyboardWillShow(notification:NSNotification){

var userInfo = notification.userInfo!
var keyboardFrame:CGRect = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue()
keyboardFrame = self.view.convertRect(keyboardFrame, fromView: nil)

var contentInset:UIEdgeInsets = self.scrollView.contentInset
contentInset.bottom = keyboardFrame.size.height
self.scrollView.contentInset = contentInset
}

func keyboardWillHide(notification:NSNotification){

var contentInset:UIEdgeInsets = UIEdgeInsetsZero
self.scrollView.contentInset = contentInset
}
0
user6193496