Como faço para rolar o UIScrollView quando o teclado aparece?

107

Estou tendo problemas com meu código. Estou tentando mover o UIScrollViewquando estou editando um UITextFieldque deve estar oculto pelo teclado pop.

Estou movendo o quadro principal agora porque não sei como 'rolar para cima' no código. Então, eu fiz um pouco de código, está funcionando bem, mas quando eu edito um UItextfield e mudo para outro UITextFieldsem pressionar o botão 'voltar', a visualização principal vai muuuuito para cima.

Fiz um NSLog()com minhas variáveis ​​size, distance e textFieldRect.origin.y como você pode ver abaixo. Quando coloco dois UITextFieldno mesmo lugar (origem y) e faço essa 'troca' específica (sem pressionar Enter), obtenho os mesmos números, enquanto meu código funcionou bem para a primeira UITextFieldedição, mas não para a segunda edição.

Veja isso:

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

Alguma ideia ?

frénésie
fonte

Respostas:

204

A maneira recomendada da Apple é alterar o contentInsetdo UIScrollView. É uma solução muito elegante, porque você não precisa mexer com o contentSize. O código a seguir foi copiado do Guia de programação do teclado , onde o tratamento desse problema é explicado. Você deveria dar uma olhada nisso.

// 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;
}

Versão Swift:

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
}
Masa
fonte
2
Ah ok. Sry, não entendi que você estava falando sobre a parte de rolagem. Sim, o activeField é apenas um espaço reservado para sua propriedade UITextField. Portanto, substitua-o e tente novamente. Você não precisa mudar o tamanho, senão o textField realmente ficará maior em altura.
Masa
2
Na verdade, você não deseja sobrescrever o contentInsets.top existente; se fizer isso, sua visualização pode deslizar para trás da navegação.
SwiftArchitect
6
github.com/michaeltyson/TPKeyboardAvoiding Esta é uma solução super simples
Pramod
2
É bom converter activeField.framepara quadro relativo, pois activeFieldnão precisa ser filho imediato dele self.view. O código atualizado deve ser semelhante a: CGRect aRect = self.view.frame; aRect.size.height -= kbSize.height; CGRect relativeFieldFrame = [activeField convertRect:activeField.frame toView:self.view]; if (!CGRectContainsPoint(aRect, relativeFieldFrame.origin) ) { CGPoint scrollPoint = CGPointMake(0.0, relativeFieldFrame.origin.y-kbSize.height); [self.mainView.scrollView setContentOffset:scrollPoint animated:YES]; }
paxx
4
Eu tive que usar a UIKeyboardFrameEndUserInfoKeychave no iOS 11 porque UIKeyboardFrameBeginUserInfoKeymuitas vezes me dava uma altura de zero.
Collin de
66

Acabei de implementar isso com o Swift 2.0 para iOS9 no Xcode 7 (beta 6), funciona bem aqui.

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
}

Editado para Swift 3

Parece que você só precisa definir o contentInsete scrollIndicatorInsetcom o Swift 3, o scrolling / contentOffset é feito automaticamente.

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
}
Johannes
fonte
Você poderia explicar seu código, por favor? Eu tenho dois campos de texto e, uma vez que edito o primeiro, ele rola para baixo enquanto o segundo textField rola para cima.
CAN de
No iPad, isso move a visualização de rolagem para baixo em vez de para cima. Alguma ideia do que está acontecendo aí?
Justin Vallely
2
@can o textField referido é uma variável que você definiu para seu viewcontroller com base no primeiro respondente atual
Johannes
Eu me pergunto por que a Apple decidiu rolar o campo de texto ativo acima do teclado para nós agora.
paulvs
2
no swift 4 coloque @objc nos métodos keyboardWillShow e keyboardWillHide
Ronaldo Albertini
16

Todas as respostas aqui parecem esquecer as possibilidades da paisagem. Se você quiser que isso funcione quando o dispositivo for girado para uma visualização de paisagem, você terá problemas.

O truque aqui é que, embora a visualização reconheça a orientação, o teclado não. Isso significa que em paisagem, a largura do teclado é na verdade sua altura e vice-versa.

Para modificar a maneira recomendada pela Apple de alterar as inserções de conteúdo e obter suporte para a orientação paisagem, eu recomendaria usar o seguinte:

// 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;
}

A parte a se prestar atenção aqui é a seguinte:

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

O que faz é detectar em qual orientação o dispositivo está. Se for paisagem, ele irá 'trocar' os valores de largura e altura da variável keyboardSize para garantir que os valores corretos estejam sendo usados ​​em cada orientação.

Roubar
fonte
bem, você pode querer fazer um ajuste extra (redução) da parte inferior da inserção de conteúdo de acordo com este stackoverflow.com/questions/25704513/… caso o rolador esteja ocupando toda a altura da tela UIEdgeInsetsMake (0,0, 0,0, kbSize.height - ([UIScreen mainScreen] .bounds.size.height - cvf.origin.y - cvf.size.height), 0,0); onde cvf é o scroller.frame
Anton Tropashko
if ( idance == UIInterfaceOrientationLandscapeLeft || customization == UIInterfaceOrientationLandscapeRight )
schmidt9
13

Solução Swift 4 :

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
}

fonte
3
funcionou principalmente, só precisava mudar UIKeyboardFrameBeginUserInfoKeyparaUIKeyboardFrameEndUserInfoKey
Fonix
Eu aplico este código em UITableView. Mas TableView não está rolando para cima imediatamente.
Shawn Baek
3
UIKeyboardWillShow, UIKeyboardWillHideE UIKeyboardFrameBeginUserInfoKeyforam renomeados para UIResponder.keyboardWillShowNotification, UIResponder.keyboardWillHideNotification, e UIResponder.keyboardFrameBeginUserInfoKey.
Aaron Brager
9

Para isso, não há necessidade de muita codificação, é muito fácil como o código abaixo: -

seu texto todo arquivado em UIScrollview da ponta como esta imagem: -

insira a descrição da imagem aqui

YourViewController.h

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

conecte IBOutlet do nib e também conecte cada delegado de UItextfiled e scrollview delegado do NIB

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

NOTA se o delegado arquivado por texto não estiver conectado, então nenhum método está funcionando, certifique-se de que todos os iBOulate e delegado estejam conectados corretamente

Nitin Gohel
fonte
5
Esta é uma abordagem muito antiga e não deve ser usada. Baseia-se em valores codificados e suposições que não são mais relevantes.
Womble de
@Womble Existem muitas respostas que são antigas, mas relevantes para a pergunta naquele momento (quando a pergunta foi feita). Portanto, não vote contra sem as razões.
Ashish Kakkad
7

Recomendação da Apple recodificada em Swift + Usando UIScrollView com Auto Layout no iOS (com base nos seguintes 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)
    }

}
O rei da bruxaria
fonte
Após um dia de trabalho árduo consegui implementar a recomendação da apple no Swift + modifiquei um pouco o código deles + ajustei tornando-o responsivo em todos os dispositivos da apple, então antes de votar, por favor me diga o porquê. Nenhum dos códigos acima funciona corretamente em todos os dispositivos e todas as situações de layout. No entanto, o meu funciona em todos os dispositivos Apple e situações de layout.
King-Wizard
Suponho que você também precise cancelar a assinatura do centro de notificação antes que a visualização morra.
Cyril Duchon-Doris
4

A única coisa que eu atualizaria no código da Apple é o método keyboardWillBeHidden: para fornecer uma transição suave.

// 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;

}
Jovan Stankovic
fonte
4

Aqui está uma resposta compatível com Swift 3 , que também funcionará com controladores de visualização dentro de um controlador de navegação - pois eles irão alterar a contentInset.toppropriedade de visualização de rolagem .

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
}
rdougan
fonte
4

Solução Swift 4.2 que leva em conta as alturas possíveis de UIToolbar e UITabBar.

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
}

E, se você tiver como alvo o <iOS 9, terá que cancelar o registro do observador em algum momento (obrigado Joe )

JanApotheker
fonte
Ele leva em consideração o espaço na barra de guias do iPhone X? É onde aparece a faixa do iOS.
surfrider
iOS9 + você não precisa remover o observador developer.apple.com/documentation/foundation/notificationcenter/…
Joe
Sim, você está certo. Eu atualizei a resposta de acordo.
JanApotheker
3

Descobri que as respostas acima estão desatualizadas. Também não é perfeito ao rolar.

Aqui está uma versão rápida.

Ele rolará para a direita abaixo do textField, sem espaço livre. E ele vai restaurar a forma como era como na primeira vez.

//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)
}
Ronan
fonte
Rola um pouco para cima, mas não o suficiente para expor toda a altura. Estou usando o Swift 2.3 e testando-o no iphone 5.
KMC
2

É isso que estou usando. É simples e funciona bem.

#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);
    }];
}

Use a UITextFieldchamada de delegado textFieldDidBeginEditing:para mudar sua visão para cima e também adicione um observador de notificação para retornar a visão ao normal quando o teclado se esconde:

-(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];
}
lobianco
fonte
2

Este é o código final com melhorias em 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
}
Anjaneyulu Battula
fonte
1
Acho que sua lógica está invertida - você só deseja rolar se CGRectContainsPoint NÃO contiver o relativeFieldFrame.origin.
Rayfleck
2

Uma das soluções mais fáceis é usar o seguinte protocolo:

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

Quando você quiser usar este protocolo, você só precisa estar em conformidade com ele e atribuir sua visualização de rolagem em seu controlador da seguinte forma:

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

}
Soheil Novinfard
fonte
1

Eu faria isso assim. É muito código, mas garante que o textField atualmente em foco esteja centralizado verticalmente no 'espaço disponível':

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

Observe que a - (IBAction)textFieldGotFocus:ação está ligada a cada DidBeginEditingestado de textField .

Além disso, seria um pouco melhor obter a duração da animação da notificação do teclado e usá-la para a animação scrollview em vez de um valor fixo, mas me processe, isso foi bom o suficiente para mim;)

Tobi
fonte
1

Use a seguinte extensão se não quiser calcular muito:

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

E talvez você queira manter seu UITextField sempre visível:

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

Experimente este código no 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)
    }
Naveen Kumar M
fonte
1

Solução Swift 5 baseada na solução Masa acima - mudanças em relação a ela:

  • usando em keyboardFrameEndUserInfoKeyvez de keyboardFrameBeginUserInfoKey, porque keyboardFrameBeginUserInfoKeypode na primeira exibição retornar outro valor, conforme descrito por exemplo aqui: a altura do teclado varia quando aparece
  • usando "irá" em vez de notificações "fez", além de alterá-lo para nomes de teclas Swift 5: UIResponder.keyboardWillShowNotification/ em UIResponder.keyboardWillHideNotificationvez de NSNotification.Name.UIKeyboardDidShow/NSNotification.Name.UIKeyboardDidHide

Código:

override func viewDidLoad() {
    super.viewDidLoad()
    registerForKeyboardNotifications()
}

func registerForKeyboardNotifications() {
    NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardAppear(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardDisappear(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}

@objc func onKeyboardAppear(_ notification: NSNotification) {
    guard let info = notification.userInfo, let kbSize = (info[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size else { return }

    let insets = UIEdgeInsets(top: 0, left: 0, bottom: kbSize.height, right: 0)

    scrollView.contentInset = insets
    scrollView.scrollIndicatorInsets = insets

    //Other changes if needed
}

deinit {
    NotificationCenter.default.removeObserver(self)
}
Mikolaj
fonte
0

Na verdade, você não precisa de um UIScrollView para fazer isso. Usei este código e funciona para mim:

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

                 }];
}
Timur Mustafaev
fonte
Problemas: usa valores embutidos em código. Muda toda a sua IU para cima e para baixo, o que geralmente bagunça a aparência da visualização.
assuntos de significado
0

Você pode rolar usando a propriedade contentOffsetem UIScrollView, por exemplo,

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

Também existe um método para fazer a rolagem animada.

Quanto à razão pela qual sua segunda edição não está rolando corretamente, pode ser porque você parece assumir que um novo teclado aparecerá toda vez que a edição começar. Você pode tentar verificar se já ajustou para a posição visível do "teclado" (e da mesma forma verificar a visibilidade do teclado no momento, antes de reverter).

Uma solução melhor pode ser ouvir a notificação do teclado, por exemplo:

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

Eu sei que é uma velha questão agora, mas pensei que poderia ajudar outras pessoas. Eu queria algo um pouco mais fácil de implementar para alguns aplicativos que tinha, então criei uma aula para isso. Você pode baixá-lo aqui se desejar: https://github.com/sdernley/iOSTextFieldHandler

É tão simples quanto configurar todos os UITextFields para ter um delegado próprio

textfieldname.delegate = self;

E, em seguida, adicionar isso ao seu controlador de visualização com o nome do seu scrollView e botão de envio

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

A seguir estão minhas soluções que funcionam (5 etapas)

Passo 1: Adicionar um observador para capturar qual UITEXTFIELD ou UITEXTVIEW ShoudBeginEditing (onde o objeto é iniciado ou ViewDidLoad.

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

Passo 2: Publique uma notificação quando ..ShouldBeginEditing with OBJECT de UITEXTFIELD ou UITEXTVIEW

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

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

Etapa 3: o método que (a Etapa 1 chama) atribui o UITEXTFIELD ou UITEXTVIEW atual

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

Etapa 4: Adicionar o observador de teclado UIKeyboardWillShowNotification (mesmo lugar da Etapa 1)

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

e método:

// 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;
    }
}

Etapa 5: Adicionar o observador de teclado UIKeyboardWillHideNotification (mesmo lugar da etapa 1)

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

e método:

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

Lembre-se de remover observadores!

Mike Zriel
fonte
0

Usei esta resposta fornecida por Sudheer Palchuri https://stackoverflow.com/users/2873919/sudheer-palchuri https://stackoverflow.com/a/32583809/6193496

Em ViewDidLoad, registre as notificações:

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

Adicione os métodos de observador abaixo que fazem a rolagem automática quando o teclado aparece.

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
}
Comunidade
fonte
0

Minha solução tem 4 etapas:
- Etapa 1: a função escuta quando o teclado aparece

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

- Etapa 2: a função escuta quando o teclado desaparece

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

- Etapa 3: adicione essas funções à central de notificações:

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

- Etapa 4: remover a escuta quando visualizar o controlador desaparecer

- (void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
Heo Đất Hades
fonte