ios - textfield delegate swift 3




Come posso far muovere UITextField quando è presente la tastiera? (20)

Con l'SDK iOS:

Ho un UIView con UITextField che fa apparire una tastiera. Ho bisogno che sia in grado di:

  1. Consentire lo scorrimento dei contenuti di UIScrollView per vedere gli altri campi di testo quando viene visualizzata la tastiera

  2. Automaticamente "salta" (scorrendo verso l'alto) o accorciando

So che ho bisogno di un UIScrollView . Ho provato a cambiare la classe del mio UIView su un UIScrollView ma non riesco ancora a scorrere le caselle di testo verso l'alto o verso il basso.

Ho bisogno sia di un UIView che di un UIScrollView ? Si va dentro l'altro?

Cosa deve essere implementato per scorrere automaticamente al campo di testo attivo?

Idealmente la maggior parte della configurazione dei componenti sarà eseguita in Interface Builder. Mi piacerebbe solo scrivere il codice per quello che serve.

Nota: l' UIView (o UIScrollView ) con cui sto lavorando viene visualizzato da una barra delle linguette ( UITabBar ), che deve funzionare normalmente.

Modifica: sto aggiungendo la barra di scorrimento solo per quando viene visualizzata la tastiera. Anche se non è necessario, mi sembra che fornisca un'interfaccia migliore perché, ad esempio, l'utente può scorrere e modificare le caselle di testo.

Ho funzionato dove cambio la dimensione del frame di UIScrollView quando la tastiera va su e giù. Sto semplicemente usando:

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

Tuttavia, questo non si sposta automaticamente verso l'alto o centra i campi di testo inferiori nell'area visibile, che è quello che mi piacerebbe davvero.


Per i programmatori Swift :

Questo farà tutto per te, basta metterli nella classe del tuo controller di visualizzazione e implementare UITextFieldDelegate sul tuo controller di visualizzazione e impostare il delegato del textField su self

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

Implementare i metodi di callback delegati:

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

Qui ho trovato la soluzione più semplice per gestire la tastiera.

Devi solo copiare e incollare sotto il codice di esempio e modificare il tuo campo di testo o qualsiasi vista che vuoi spostare.

Passo 1

Basta copiare e incollare sotto due metodi nel tuo controller

- (void)registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:)
                                                 name:UIKeyboardDidShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillBeHidden:)
                                                 name:UIKeyboardWillHideNotification object:nil];
}

- (void)deregisterFromKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

Passo 2

registra e cancella le Notifiche della tastiera in viewWillAppear e viewWillDiseparano i metodi rispettivamente.

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self registerForKeyboardNotifications];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [self deregisterFromKeyboardNotifications];
    [super viewWillDisappear:animated];
}

Step-3

Ecco la parte dell'anima, basta sostituire il campo di testo e modificare l'altezza di quanto vuoi spostare al rialzo.

- (void)keyboardWasShown:(NSNotification *)notification
{
    NSDictionary* info = [notification userInfo];
    CGSize currentKeyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    //you need replace your textfield instance here
    CGPoint textFieldOrigin = self.tokenForPlaceField.frame.origin;
    CGFloat textFieldHeight = self.tokenForPlaceField.frame.size.height;

    CGRect visibleRect = self.view.frame;
    visibleRect.size.height -= currentKeyboardSize.height;

    if (!CGRectContainsPoint(visibleRect, textFieldOrigin))
    {
        //you can add yor desired height how much you want move keypad up, by replacing "textFieldHeight" below

        CGPoint scrollPoint = CGPointMake(0.0, textFieldOrigin.y - visibleRect.size.height  + textFieldHeight); //replace textFieldHeight to currentKeyboardSize.height, if you want to move up with more height
        [self.scrollView setContentOffset:scrollPoint animated:YES];
    }
}

- (void)keyboardWillBeHidden:(NSNotification *)notification
{
    [self.scrollView setContentOffset:CGPointZero animated:YES];
}

Riferimento : bene, per favore apprezzare questo ragazzo , che ha condiviso questo bel codice snip, soluzione pulita.

Spero che questo possa essere utile a qualcuno là fuori.


Avevo anche un sacco di problemi con un UIScrollView componeva più UITextFields , dei quali uno o più di essi sarebbero stati oscurati dalla tastiera quando sono stati modificati.

Ecco alcune cose da considerare se il tuo UIScrollView non sta scorrendo correttamente.

1) Assicurati che contentSize sia maggiore della dimensione del frame di UIScrollView . Il modo per capire UIScrollViews è che UIScrollView è come una finestra di visualizzazione sul contenuto definito in contentSize. Quindi, per consentire a UIScrollview di scorrere ovunque, il contentSize deve essere maggiore di UIScrollView . Altrimenti, non è richiesto lo scorrimento poiché tutto ciò che è definito in contentSize è già visibile. BTW, default contentSize = CGSizeZero .

2) Ora che hai capito che UIScrollView è davvero una finestra sul tuo "contenuto", il modo per assicurarti che la tastiera non UIScrollView's "finestra" UIScrollView's visualizzazione UIScrollView's sarebbe quella di ridimensionare l' UIScrollView modo che quando la tastiera è presente, tu avere la finestra di UIScrollView dimensionata per il solo UIScrollView originale frame.size.height meno l'altezza della tastiera. Questo assicurerà che la tua finestra sia solo quella piccola area visibile.

3) Ecco il trucco: quando l'ho implementato per la prima volta ho pensato che avrei dovuto ottenere il CGRect del campo di testo modificato e chiamare UIScrollView's metodo scrollRecToVisible UIScrollView's . Ho implementato il metodo UITextFieldDelegate textFieldDidBeginEditing con la chiamata al metodo scrollRecToVisible . Questo in realtà ha funzionato con uno strano effetto collaterale che lo scorrimento avrebbe fatto scattare l' UITextField in posizione. Per molto tempo non sono riuscito a capire cosa fosse. Poi ho commentato il metodo textFieldDidBeginEditing Delegate e tutto funziona !! (???). Come si è scoperto, credo che UIScrollView UITextField implicitamente l' UITextField attualmente modificato nella finestra visibile implicitamente. La mia implementazione del metodo UITextFieldDelegate e la successiva chiamata a scrollRecToVisible era ridondante ed era la causa dello strano effetto collaterale.

Ecco quindi i passaggi per far scorrere correttamente il tuo UITextField in un UIScrollView in posizione quando appare la tastiera.

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.

- (void)viewDidLoad 
{
    [super viewDidLoad];

    // register for keyboard notifications
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(keyboardWillShow:) 
                                                 name:UIKeyboardWillShowNotification 
                                               object:self.view.window];
    // register for keyboard notifications
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(keyboardWillHide:) 
                                                 name:UIKeyboardWillHideNotification 
                                               object:self.view.window];
    keyboardIsShown = NO;
    //make contentSize bigger than your scrollSize (you will need to figure out for your own use case)
    CGSize scrollContentSize = CGSizeMake(320, 345);
    self.scrollView.contentSize = scrollContentSize;
}

- (void)keyboardWillHide:(NSNotification *)n
{
    NSDictionary* userInfo = [n userInfo];

    // get the size of the keyboard
    CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;


    // resize the scrollview
    CGRect viewFrame = self.scrollView.frame;
    // I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
    viewFrame.size.height += (keyboardSize.height - kTabBarHeight);

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [self.scrollView setFrame:viewFrame];
    [UIView commitAnimations];

    keyboardIsShown = NO;
}

- (void)keyboardWillShow:(NSNotification *)n
{
    // This is an ivar I'm using to ensure that we do not do the frame size adjustment on the `UIScrollView` if the keyboard is already shown.  This can happen if the user, after fixing editing a `UITextField`, scrolls the resized `UIScrollView` to another `UITextField` and attempts to edit the next `UITextField`.  If we were to resize the `UIScrollView` again, it would be disastrous.  NOTE: The keyboard notification will fire even when the keyboard is already shown.
    if (keyboardIsShown) {
        return;
    }

    NSDictionary* userInfo = [n userInfo];

    // get the size of the keyboard
    CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;

    // resize the noteView
    CGRect viewFrame = self.scrollView.frame;
    // I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
    viewFrame.size.height -= (keyboardSize.height - kTabBarHeight);

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [self.scrollView setFrame:viewFrame];
    [UIView commitAnimations];
    keyboardIsShown = YES;
}
  1. Registrati per le notifiche della tastiera su viewDidLoad
  2. Annullare la registrazione per il nofitication della tastiera in viewDidUnload
  3. Assicurati che contentSize sia impostato e maggiore di UIScrollView su viewDidLoad
  4. Riduci UIScrollView quando è presente la tastiera
  5. Ripristina UIScrollView quando la tastiera si spegne.
  6. Usa un ivar per rilevare se la tastiera è già mostrata sullo schermo poiché le notifiche della tastiera vengono inviate ogni volta che un UITextField viene UITextField schede anche se la tastiera è già presente per evitare di restringere l' UIScrollView quando è già ridotto

Una cosa da notare è che UIKeyboardWillShowNotification si UIKeyboardWillShowNotification anche quando la tastiera è già sullo schermo quando si fa tabulazione su un altro UITextField . Mi sono occupato di questo utilizzando un ivar per evitare di ridimensionare UIScrollView quando la tastiera è già sullo schermo. Il ridimensionamento inavvertitamente di UIScrollView quando la tastiera è già presente sarebbe disastroso!

Spero che questo codice ti risparmi un sacco di mal di testa.


Ci sono già molte risposte, ma ancora nessuna delle soluzioni di cui sopra aveva tutte le fantasiose funzionalità di posizionamento richieste per un'animazione "perfetta" priva di errori, retrocompatibile e priva di sfarfallio. (bug durante l'animazione di frame / bounds e contentOffset insieme, diversi orientamenti di interfaccia, tastiera split di iPad, ...)
Lasciatemi condividere la mia soluzione:
(presumendo che tu abbia configurato 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];
}

In textFieldDidBeginEditting e in textFieldDidEndEditing chiama la funzione [self animateTextField:textField up:YES] modo:

-(void)textFieldDidBeginEditing:(UITextField *)textField 
{ 
    [self animateTextField:textField up:YES]; 
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
    [self animateTextField:textField up:NO];
}

-(void)animateTextField:(UITextField*)textField up:(BOOL)up
{
    const int movementDistance = -130; // tweak as needed
    const float movementDuration = 0.3f; // tweak as needed

    int movement = (up ? movementDistance : -movementDistance); 

    [UIView beginAnimations: @"animateTextField" context: nil];
    [UIView setAnimationBeginsFromCurrentState: YES];
    [UIView setAnimationDuration: movementDuration];
    self.view.frame = CGRectOffset(self.view.frame, 0, movement);
    [UIView commitAnimations];
}

Spero che questo codice ti possa aiutare.

In Swift 2

func animateTextField(textField: UITextField, up: Bool) 
{
     let movementDistance:CGFloat = -130
     let movementDuration: Double = 0.3

     var movement:CGFloat = 0
     if up 
     {
         movement = movementDistance
     }
     else 
     {
         movement = -movementDistance
     }
     UIView.beginAnimations("animateTextField", context: nil)
     UIView.setAnimationBeginsFromCurrentState(true)
     UIView.setAnimationDuration(movementDuration)
     self.view.frame = CGRectOffset(self.view.frame, 0, movement)
     UIView.commitAnimations()
}


func textFieldDidBeginEditing(textField: UITextField) 
{
    self.animateTextField(textField, up:true)
}

func textFieldDidEndEditing(textField: UITextField) 
{
    self.animateTextField(textField, up:false)
}

SWIFT 3

 func animateTextField(textField: UITextField, up: Bool)
    {
        let movementDistance:CGFloat = -130
        let movementDuration: Double = 0.3

        var movement:CGFloat = 0
        if up
        {
            movement = movementDistance
        }
        else
        {
            movement = -movementDistance
        }
        UIView.beginAnimations("animateTextField", context: nil)
        UIView.setAnimationBeginsFromCurrentState(true)
        UIView.setAnimationDuration(movementDuration)
        self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
        UIView.commitAnimations()
    }


    func textFieldDidBeginEditing(textField: UITextField)
    {
        self.animateTextField(textField: textField, up:true)
    }

    func textFieldDidEndEditing(textField: UITextField)
    {
        self.animateTextField(textField: textField, up:false)
    }

In realtà è meglio usare l'implementazione di Apple, come previsto nei docs . Tuttavia, il codice che forniscono è difettoso. Sostituisci la parte trovata in keyboardWasShown: appena sotto i commenti al seguente:

NSDictionary* info = [aNotification userInfo];
CGRect keyPadFrame=[[UIApplication sharedApplication].keyWindow convertRect:[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue] fromView:self.view];
CGSize kbSize =keyPadFrame.size;
CGRect activeRect=[self.view convertRect:activeField.frame fromView:activeField.superview];
CGRect aRect = self.view.bounds;
aRect.size.height -= (kbSize.height);

CGPoint origin =  activeRect.origin;
origin.y -= backScrollView.contentOffset.y;
if (!CGRectContainsPoint(aRect, origin)) {
    CGPoint scrollPoint = CGPointMake(0.0,CGRectGetMaxY(activeRect)-(aRect.size.height));
    [backScrollView setContentOffset:scrollPoint animated:YES];
}

I problemi con il codice Apple sono i seguenti: (1) Calcolano sempre se il punto si trova all'interno del frame della vista, ma è un ScrollView , quindi potrebbe già averlo fatto scorrere ed è necessario tenere conto di tale offset:

origin.y -= scrollView.contentOffset.y

(2) Spingono il contenutoOffset all'altezza della tastiera, ma vogliamo il contrario (vogliamo spostare il contentOffset base all'altezza visibile sullo schermo, non ciò che non lo è):

activeField.frame.origin.y-(aRect.size.height)

developer.apple.com/library/ios/#documentation/StringsTextFonts/… documento descrive una soluzione a questo problema. Guarda il codice sorgente sotto "Spostamento del contenuto che si trova sotto la tastiera". È piuttosto semplice.

EDIT: notato che c'è un piccolo problema nell'esempio. Probabilmente vorrai ascoltare per UIKeyboardWillHideNotificationinvece di UIKeyboardDidHideNotification. In caso contrario, la vista di scorrimento dietro alla tastiera verrà ritagliata per la durata dell'animazione di chiusura della tastiera.


Nota : questa risposta presuppone che il campo di testo sia in una scrollView.

Preferisco occuparmi di questo usando scrollContentInset e scrollContentOffset invece di scherzare con i frame della mia vista.

Prima ascoltiamo le notifiche della tastiera

//call this from viewWillAppear
-(void)addKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShow:)
                                                 name:UIKeyboardWillShowNotification
                                               object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillHide:)
                                                 name:UIKeyboardWillHideNotification
                                               object:nil];
}
//call this from viewWillDisappear
-(void)removeKeyboardNotifications{
    [[NSNotificationCenter default
    Center] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

Il passo successivo è mantenere una proprietà che rappresenti il ​​primo risponditore corrente (UITextfield / UITextVIew che al momento ha la tastiera).

Utilizziamo i metodi delegati per impostare questa proprietà. Se stai usando un altro componente, avrai bisogno di qualcosa di simile.

Si noti che per il campo di testo lo abbiamo impostato in didBeginEditing e per textView in shouldBeginEditing. Questo perché textViewDidBeginEditing viene chiamato dopo UIKeyboardWillShowNotification per qualche motivo.

-(BOOL)textViewShouldBeginEditing:(UITextView * )textView{
    self.currentFirstResponder = textView;
    return YES;
}

-(void)textFieldDidBeginEditing:(UITextField *)textField{
    self.currentFirstResponder = textField;
}

Finalmente, ecco la magia

- (void)keyboardWillShow:(NSNotification*)aNotification{
    NSDictionary* info = [aNotification userInfo];
    CGRect kbFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];


    /*if currentFirstResponder is overlayed by the keyboard, move it so it bottom ends where the keyboard begins*/
    if(self.currentFirstResponder){

        //keyboard origin in currentFirstResponderFrame
        CGPoint keyboardOrigin = [self.currentFirstResponder convertPoint:kbFrame.origin fromView:nil];

        float spaceBetweenFirstResponderAndKeyboard = abs(self.currentFirstResponder.frame.size.height-keyboardOrigin.y);

        //only scroll the scrollview if keyboard overlays the first responder
        if(spaceBetweenFirstResponderAndKeyboard>0){
            //if i call setContentOffset:animate:YES it behaves differently, not sure why
            [UIView animateWithDuration:0.25 animations:^{
                [self.scrollView setContentOffset:CGPointMake(0,self.scrollView.contentOffset.y+spaceBetweenFirstResponderAndKeyboard)];
            }];
        }
    }

    //set bottom inset to the keyboard height so you can still scroll the whole content

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbFrame.size.height, 0.0);
    _scrollView.contentInset = contentInsets;
    _scrollView.scrollIndicatorInsets = contentInsets;

}

- (void)keyboardWillHide:(NSNotification*)aNotification{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    _scrollView.contentInset = contentInsets;
    _scrollView.scrollIndicatorInsets = contentInsets;
}

Swift 4 .

È possibile scorrere facilmente su e giù UITextFieldO UIViewCon UIKeyBoardConAnimation

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet var textField: UITextField!
    @IBOutlet var chatView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: .UIKeyboardWillChangeFrame, object: nil)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        textField.resignFirstResponder()
    }

    @objc func keyboardWillChange(notification: NSNotification) {

        let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
        let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
        let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
        let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
        let deltaY = targetFrame.origin.y - curFrame.origin.y
        print("deltaY",deltaY)

        UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
            self.chatView.frame.origin.y+=deltaY // Here You Can Change UIView To UITextField
        },completion: nil)
    }

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

}

Trovata la soluzione più semplice

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    [self animateTextField: textField up: YES];
}


- (void)textFieldDidEndEditing:(UITextField *)textField
{
    [self animateTextField: textField up: NO];
}

- (void) animateTextField: (UITextField*) textField up: (BOOL) up
{
    const int movementDistance = 80; // tweak as needed
    const float movementDuration = 0.3f; // tweak as needed

    int movement = (up ? -movementDistance : movementDistance);

    [UIView beginAnimations: @"anim" context: nil];
    [UIView setAnimationBeginsFromCurrentState: YES];
    [UIView setAnimationDuration: movementDuration];
    self.view.frame = CGRectOffset(self.view.frame, 0, movement);
    [UIView commitAnimations];
}

Per riportare allo stato di visualizzazione originale, aggiungere:

-(void)textFieldDidEndEditing:(UITextField *)sender

{
    //move the main view, so that the keyboard does not hide it.
    if  (self.view.frame.origin.y < 0)
    {
        [self setViewMovedUp:NO];
    }
}

Piccola correzione che funziona per molti campi UIText

#pragma mark UIKeyboard handling

#define kMin 150

-(void)textFieldDidBeginEditing:(UITextField *)sender
{
   if (currTextField) {
      [currTextField release];
   }
   currTextField = [sender retain];
   //move the main view, so that the keyboard does not hide it.
   if (self.view.frame.origin.y + currTextField.frame.origin. y >= kMin) {
        [self setViewMovedUp:YES]; 
   }
}



//method to move the view up/down whenever the keyboard is shown/dismissed
-(void)setViewMovedUp:(BOOL)movedUp
{
   [UIView beginAnimations:nil context:NULL];
   [UIView setAnimationDuration:0.3]; // if you want to slide up the view

   CGRect rect = self.view.frame;
   if (movedUp)
   {
      // 1. move the view's origin up so that the text field that will be hidden come above the keyboard 
      // 2. increase the size of the view so that the area behind the keyboard is covered up.
      rect.origin.y = kMin - currTextField.frame.origin.y ;
   }
   else
   {
      // revert back to the normal state.
      rect.origin.y = 0;
   }
   self.view.frame = rect;

   [UIView commitAnimations];
}


- (void)keyboardWillShow:(NSNotification *)notif
{
   //keyboard will be shown now. depending for which textfield is active, move up or move down the view appropriately

   if ([currTextField isFirstResponder] && currTextField.frame.origin.y + self.view.frame.origin.y >= kMin)
   {
      [self setViewMovedUp:YES];
   }
   else if (![currTextField isFirstResponder] && currTextField.frame.origin.y  + self.view.frame.origin.y < kMin)
   {
      [self setViewMovedUp:NO];
   }
}

- (void)keyboardWillHide:(NSNotification *)notif
{
   //keyboard will be shown now. depending for which textfield is active, move up or move down the view appropriately
   if (self.view.frame.origin.y < 0 ) {
      [self setViewMovedUp:NO];
   }

}


- (void)viewWillAppear:(BOOL)animated
{
   // register for keyboard notifications
   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) 
                                                name:UIKeyboardWillShowNotification object:self.view.window]; 
   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) 
                                                name:UIKeyboardWillHideNotification object:self.view.window]; 
}

- (void)viewWillDisappear:(BOOL)animated
{
   // unregister for keyboard notifications while not visible.
   [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; 
}

Usa questa terza parte che non è necessario scrivere anche una sola riga

github.com/hackiftekhar/IQKeyboardManager

scarica il progetto e trascina IQKeyboardManager nel tuo progetto. Se trovi qualche problema per favore leggi il documento README.

Ragazzi davvero il suo mal di testa rimuovere per gestire la tastiera ..

Grazie e buona fortuna!


prova questo breve trucco ...

 - (void)textFieldDidBeginEditing:(UITextField *)textField
    {
        [self animateTextField: textField up: YES];
    }

    - (void)textFieldDidEndEditing:(UITextField *)textField
    {
        [self animateTextField: textField up: NO];
    }

    - (void) animateTextField: (UITextField*) textField up: (BOOL) up
    {
        const int movementDistance = textField.frame.origin.y / 2; // tweak as needed
        const float movementDuration = 0.3f; // tweak as needed

        int movement = (up ? -movementDistance : movementDistance);

        [UIView beginAnimations: @"anim" context: nil];
        [UIView setAnimationBeginsFromCurrentState: YES];
        [UIView setAnimationDuration: movementDuration];
        self.view.frame = CGRectOffset(self.view.frame, 0, movement);
        [UIView commitAnimations];
    }

Codifica felice:) ....


Come per i documenti , a partire da iOS 3.0, la UITableViewControllerclasse ridimensiona automaticamente e riposiziona la sua vista tabella quando è in corso la modifica dei campi di testo. Penso che non sia sufficiente inserire il campo di testo all'interno di un UITableViewCellcome alcuni hanno indicato.

Dai documenti :

Un controller di visualizzazione tabella supporta la modifica in linea delle righe di visualizzazione tabella; se, ad esempio, le righe hanno campi di testo incorporati in modalità di modifica, scorre la riga in corso di modifica sopra la tastiera virtuale che viene visualizzata.


Ecco la soluzione di hacking che mi è venuta in mente per un layout specifico. Questa soluzione è simile alla soluzione di Matt Gallagher in quanto consente di scorrere una sezione in vista. Sono ancora nuovo nello sviluppo di iPhone e non ho familiarità con il funzionamento dei layout. Quindi, questo hack.

La mia implementazione era necessaria per supportare lo scorrimento quando si fa clic in un campo e si scorre anche quando l'utente seleziona la prossima volta sulla tastiera.

Ho avuto un UIView con un'altezza di 775. I controlli sono distribuiti fondamentalmente in gruppi di 3 su un grande spazio. Ho finito con il seguente layout IB.

UIView -> UIScrollView -> [UI Components]

Ecco che arriva l'hack

Ho impostato l'altezza di UIScrollView su 500 unità più grandi rispetto al layout effettivo (1250). Ho quindi creato un array con le posizioni assolute di cui ho bisogno per scorrere e una semplice funzione per ottenerle in base al numero del tag IB.

static NSInteger stepRange[] = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 140, 140, 140, 140, 410
};

NSInteger getScrollPos(NSInteger i) {
    if (i < TXT_FIELD_INDEX_MIN || i > TXT_FIELD_INDEX_MAX) {
        return 0 ;
    return stepRange[i] ;
}

Ora tutto ciò che devi fare è usare le seguenti due linee di codice in textFieldDidBeginEditing e textFieldShouldReturn (quest'ultimo se stai creando un prossimo campo di navigazione)

CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ;
[self.scrollView setContentOffset:point animated:YES] ;

Un esempio.

- (void) textFieldDidBeginEditing:(UITextField *)textField
{
    CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ;
    [self.scrollView setContentOffset:point animated:YES] ;
}


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

    NSInteger nextTag = textField.tag + 1;
    UIResponder* nextResponder = [textField.superview viewWithTag:nextTag];

    if (nextResponder) {
        [nextResponder becomeFirstResponder];
        CGPoint point = CGPointMake(0, getScrollPos(nextTag)) ;
        [self.scrollView setContentOffset:point animated:YES] ;
    }
    else{
        [textField resignFirstResponder];
    }

    return YES ;
}

Questo metodo non "scorre indietro" come fanno altri metodi. Questo non era un requisito. Ancora una volta questo era per un UIView abbastanza 'alto', e non avevo giorni per imparare i motori di layout interni.


Non richiede una vista di scorrimento per poter spostare la cornice della vista. È possibile modificare la cornice di una viewcontroller'svista in modo che l'intera vista si sollevi quanto basta per posizionare il campo di testo firstresponder sopra la tastiera. Quando mi sono imbattuto in questo problema, ho creato una sottoclasse di UIViewControllerquesto. Osserva che la tastiera apparirà come notifica e troverà la prima sottoview del risponditore e (se necessario) animerà la vista principale verso l'alto quel tanto che basta affinché il primo risponditore si trovi sopra la tastiera. Quando la tastiera si nasconde, anima la vista indietro dove si trovava.

Per utilizzare questa sottoclasse, crea il tuo controller di visualizzazione personalizzato come sottoclasse di GMKeyboardVC e eredita questa funzione (assicurati solo di implementare viewWillAppeare viewWillDisappeardevono chiamare super). La lezione è su github .


Non sono sicuro se spostare la vista verso l'alto sia l'approccio corretto, l'ho fatto in modo diverso, ridimensionando l'UIScrollView. L'ho spiegato nei dettagli su un piccolo article


Shiun ha dichiarato: "Come si è scoperto, credo che UIScrollView implichi implicitamente l'UITextField attualmente modificato nella finestra visibile implicitamente" Questo sembra essere vero per iOS 3.1.3, ma non 3.2, 4.0 o 4.1. Ho dovuto aggiungere un scrollRectToVisible esplicito per rendere visibile UITextField su iOS> = 3.2.


State cercando un buon tutorial per i principianti sull'argomento, ho trovato il miglior tutorial here .

Nel MIScrollView.hesempio, al fondo del tutorial assicurarsi di inserire uno spazio a

@property (nonatomic, retain) id backgroundTapDelegate;

come vedi.





uikeyboard