Mover a visualização com o teclado usando o Swift


278

Eu tenho um aplicativo que possui um campo de texto na metade inferior da exibição. Isso significa que, quando digito no campo de texto, o teclado cobre o campo de texto.

Como mover a visualização para cima enquanto digito para que eu possa ver o que estou digitando e depois movê-la de volta ao seu local original quando o teclado desaparece?

Procurei em todos os lugares, mas todas as soluções parecem estar no Obj-C, que ainda não consigo converter.

Qualquer ajuda seria muito apreciada.


A melhor maneira de fazer isso é colocar seu conteúdo dentro de um UIScrollView e , em seguida, ajustar a propriedade contentInset da exibição de rolagem pela altura do teclado quando exibido. Absolutamente não assuma a altura do teclado - use o valor da notificação "O teclado mostrará".
Nielsbot 2/10

1
De fato, os documentos da Apple mostram como fazer isso, em "Gerenciando o teclado": developer.apple.com/library/ios/documentation/StringsTextFonts/…
nielsbot

11
Acho que todas as respostas abaixo não levam em consideração um caso: e se você tiver vários campos de texto e alguns deles estiverem localizados na parte superior da tela? Usuário a qualquer hora torneiras que textfield, ele sobe além da tela, eu tenho certeza que a resposta correta deve detectar seit is actually needed to scroll view up when keyboard appears
theDC

Esta resposta é capaz de detectar se é realmente necessário rolar a exibição quando o teclado aparece, verificando se o campo de texto que está sendo editado atualmente ocupa o mesmo espaço que o teclado: stackoverflow.com/a/28813720/6749410
HirdayGupta

Respostas:


709

Aqui está uma solução, sem manipular o comutador de um campo de texto para outro:

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

func keyboardWillShow(notification: NSNotification) {            
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.frame.origin.y -= keyboardSize.height
    }            
}

func keyboardWillHide(notification: NSNotification) {
    self.view.frame.origin.y = 0
}

Para resolver isso, substitua as duas funções keyboardWillShow/Hidepor estas:

func keyboardWillShow(notification: NSNotification) {        
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() {
        if view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }        
}

func keyboardWillHide(notification: NSNotification) {
    if view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}

EDITAR PARA SWIFT 3.0:

override func viewDidLoad() {
    super.viewDidLoad()            
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)    
}

@objc func keyboardWillShow(notification: NSNotification) {        
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }        
}

@objc func keyboardWillHide(notification: NSNotification) {
    if self.view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}

EDITAR PARA SWIFT 4.0:

override func viewDidLoad() {
    super.viewDidLoad()            
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)    
}

@objc func keyboardWillShow(notification: NSNotification) {        
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }        
}

@objc func keyboardWillHide(notification: NSNotification) {
    if self.view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}

EDITAR PARA SWIFT 4.2:

override func viewDidLoad() {
    super.viewDidLoad()            
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}

@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    if self.view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}

56
Se o usuário tocar em outro campo de texto enquanto o teclado estiver presente, a visualização será empurrada para cima, causando uma área preta (o tamanho do teclado) - precisamos corrigir isso, tendo uma variável que rastreia se o teclado está presente ou não . por exemplo, se keyboardPresent == true, então não mova a origem da visualização, etc, etc #
jonprasetyo

3
@Matthew Lin usar um boolean assim as funções keyboardWillShow e se esconder funciona apenas uma vez
iluvatar_GR

11
Apenas uma sugestão, para que você não precise depurar muito como eu. Se você tiver vários campos de texto na mesma tela, o tamanho do teclado pode variar (não mostra sugestões para algumas entradas com base em suas configurações), portanto, é recomendável definir self.view.frame.origin.y = 0, sempre você dispensa o teclado. Por exemplo, ele mostraria sugestões para o campo de texto do seu email, portanto o tamanho do teclado aumentaria e não mostraria sugestões para o campo de senha, portanto o tamanho do teclado diminuiria.
Vandan Patel

36
Você precisa usar UIKeyboardFrameEndUserInfoKeye não UIKeyboardFrameBeginUserInfoKeyao obter o tamanho do teclado. Não sei por que, no momento, mas o primeiro trará resultados mais consistentes.
jshapy8

3
Por favor substitua UIKeyboardFrameBeginUserInfoKey por UIKeyboardFrameEndUserInfoKey. O primeiro fornece o quadro inicial do teclado, que chega a zero às vezes, enquanto o segundo fornece o quadro final do teclado.
Arnab

90

A maneira mais fácil que nem exige código:

  1. Faça o download do KeyboardLayoutConstraint.swift e adicione (arraste e solte) o arquivo ao seu projeto, se você ainda não estiver usando a estrutura de animação do Spring.
  2. No storyboard, crie uma restrição inferior para o modo de exibição ou campo de texto, selecione a restrição (clique duas vezes nela) e, no Identity Inspector, altere sua classe de NSLayoutConstraint para KeyboardLayoutConstraint.
  3. Feito!

O objeto se move automaticamente para cima com o teclado, em sincronia.


4
Para selecionar a restrição inferior, você também pode acessar o Size Inspector e clicar duas vezes na restrição na lista - raywenderlich.com/wp-content/uploads/2015/09/…
gammachill

3
Isso funcionou perfeito para mim. é literalmente um processo de duas etapas. 1. Adicione KeyboardLayoutConstraint.swift, 2. No storyboard, crie uma restrição inferior para o campo de exibição ou texto. NOTA: Excluí minhas restrições e adicionei apenas 1 restrição à parte inferior da exibição ou campo de texto e alterei sua classe de NSLayoutConstraint para KeyboardLayoutConstraint. Então, quaisquer visualizações / campos de texto, etc. acima, acabei de conectar as restrições desse item ao item com uma única KeyboardLayoutConstraint e o resultado foi todos os itens em exibição movidos para CIMA / BAIXO quando o Teclado Principal Aparece / Desaparece
Brian

4
Essa é a melhor solução, o código fornecido não codifica quaisquer valores, como o comprimento ou a curva da animação ou o tamanho do teclado. Também é fácil de entender.
usar o seguinte código

3
Isso está funcionando para mim, mas recebo 50px de espaço extra entre a parte superior do teclado e a parte inferior do meu scrollView. Gostaria de saber se é devido à restrição inferior da área segura que estou usando. Alguém encontrou isso?
Clifton Labrum

1
Esta foi uma resposta incrível. Design muito legal também. Uma sugestão: se suas visualizações de texto / campos de texto estiverem nas células de exibição de tabela, você poderá notar que as visualizações que possuem essa restrição saltam desajeitadamente toda vez que o usuário clica em entrar e passa para o próximo campo de texto. Você pode envolver as animações DispatchQueue.main.async {}para corrigi-las. Bom trabalho! Afirmativo!
precisa saber é o seguinte

68

Uma das respostas populares neste segmento usa o seguinte código:

func keyboardWillShow(sender: NSNotification) {
    self.view.frame.origin.y -= 150
}
func keyboardWillHide(sender: NSNotification) {
    self.view.frame.origin.y += 150
}

Há um problema óbvio em compensar sua visualização por uma quantidade estática. Ficará bonito em um dispositivo, mas ficará ruim em qualquer outra configuração de tamanho. Você precisará obter a altura dos teclados e usá-la como seu valor de deslocamento.

Aqui está uma solução que funciona em todos os dispositivos e lida com o caso em que o usuário oculta o campo de texto previsto enquanto digita.

Solução

Importante observar abaixo, estamos passando self.view.window como nosso parâmetro de objeto. Isso nos fornecerá dados do nosso teclado, como sua altura!

@IBOutlet weak var messageField: UITextField!

override func viewDidLoad() {
    super.viewDidLoad()

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

func keyboardWillHide(sender: NSNotification) {
    let userInfo: [NSObject : AnyObject] = sender.userInfo!
    let keyboardSize: CGSize = userInfo[UIKeyboardFrameBeginUserInfoKey]!.CGRectValue.size
    self.view.frame.origin.y += keyboardSize.height
}

A aparência será agradável em todos os dispositivos e o caso em que o usuário adiciona ou remove o campo de texto previsto.

func keyboardWillShow(sender: NSNotification) {
    let userInfo: [NSObject : AnyObject] = sender.userInfo!
    let keyboardSize: CGSize = userInfo[UIKeyboardFrameBeginUserInfoKey]!.CGRectValue.size
    let offset: CGSize = userInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue.size

    if keyboardSize.height == offset.height {
        UIView.animateWithDuration(0.1, animations: { () -> Void in
            self.view.frame.origin.y -= keyboardSize.height
        })
    } else {
        UIView.animateWithDuration(0.1, animations: { () -> Void in
            self.view.frame.origin.y += keyboardSize.height - offset.height
        })
    }
}

Remover observadores

Não se esqueça de remover seus observadores antes de sair da exibição para impedir a transmissão de mensagens desnecessárias.

override func viewWillDisappear(animated: Bool) {
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: self.view.window)
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: self.view.window)
}

Atualização com base na pergunta dos comentários:

Se você tiver dois ou mais campos de texto, poderá verificar se seu view.frame.origin.y está em zero.

func keyboardWillShow(sender: NSNotification) {
    let userInfo: [NSObject : AnyObject] = sender.userInfo!

    let keyboardSize: CGSize = userInfo[UIKeyboardFrameBeginUserInfoKey]!.CGRectValue.size
    let offset: CGSize = userInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue.size

    if keyboardSize.height == offset.height {
        if self.view.frame.origin.y == 0 {
            UIView.animateWithDuration(0.1, animations: { () -> Void in
                self.view.frame.origin.y -= keyboardSize.height
            })
        }
    } else {
        UIView.animateWithDuration(0.1, animations: { () -> Void in
            self.view.frame.origin.y += keyboardSize.height - offset.height
        })
    }
     print(self.view.frame.origin.y)
}

1
quando se lida com vários campos de texto, a visão continua se movendo para cima e não voltar para baixo
Mugunthan Balakrishnan

Você vai ter que mudar suas condições para a conta para os campos de texto
Dan Beaulieu

Obrigado pela resposta, eu encontrei a resposta que eu estava procurando neste segmento em estouro de pilha stackoverflow.com/questions/1126726/...
Mugunthan Balakrishnan

@MugunthanBalakrishnan obrigado por trazer isso à tona, adicionei uma solução.
22715 Dan

Oi pessoal, há um bug. Os observadores não são removidos da visualização após serem chamados em viewWillDisappear. Substitua esta linha "NSNotificationCenter.defaultCenter (). RemoveObserver (nome próprio: UIKeyboardWillHideNotification, objeto: self.view.window)" por "NSNotificationCenter.defaultCenter (). RemoveObserver (nome próprio: UIKeyboardWillHideNotification, objeto: nulo)" foi removido
rudald 20/03/19

29

Adicione isso ao seu viewcontroller. Funciona como um encanto. Apenas ajuste os valores.

override func viewDidLoad() {
    super.viewDidLoad()        
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name:NSNotification.Name.UIKeyboardWillShow, object: nil);
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name:NSNotification.Name.UIKeyboardWillHide, object: nil);
}

@objc func keyboardWillShow(sender: NSNotification) {
    self.view.frame.origin.y -= 150
}
@objc func keyboardWillHide(sender: NSNotification) {
    self.view.frame.origin.y += 150
}

Isso funciona para mim. No entanto, é um pouco irregular. Como posso fazer isso subir smoothley? também existe uma maneira de aplicá-lo apenas a um dos campos de texto, pois atualmente isso é feito para todos. :(
DannieCoderBoi

2
Pode não funcionar com o "Layout automático", por isso, considere desativá-lo.
Teodor Ciuraru 03/03

1
Isso faz com que alguns comportamentos funky com autolayout @ Josh, você está enganado
Mike

5
Não faça isso! Você não pode assumir que o teclado tem um determinado tamanho.
Nielsbot 2/10

2
Deve usar keyboardSize. O que acontece quando você tem visualizações acessórias e diferentes alturas de teclado nos dispositivos? Teclado desanexado?
Xtrinch

25

Eu melhorei um pouco as respostas para fazê-lo funcionar com diferentes teclados e diferentes visões / campos de texto em uma página:

Adicione observadores:

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

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange(notification:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}

func keyboardWillHide() {
    self.view.frame.origin.y = 0
}

func keyboardWillChange(notification: NSNotification) {

    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        if YOURTEXTVIEW.isFirstResponder {
            self.view.frame.origin.y = -keyboardSize.height
        }
    }
}

Remova os observadores:

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

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

3
esta solução funciona melhor do que a resposta aceita. Receber demonstrar resposta do teclado apenas uma vez que para mim é um bug :)
Masih

Isso funciona para o Xcode 10.1 e iOS 12. A resposta aceita não é mais válida.
zeeshan

Esta é uma excelente resposta, a única coisa que gostaria de acrescentar é manter o controle da área de segurança inferior nos dispositivos mais recentes (X, XS, etc), para que isso seja responsável.
Munib

@Munib Consulte stackoverflow.com/a/54993623/1485230 Outros problemas incluem a exibição não animada e a alteração da altura do teclado não está sendo seguida.
Antzi 5/03/19

e se o meu campo de texto estiver no topo da exibição ..? Quero dizer, se existe um campo de texto com origem Y = 0 .. ?? depois textField está indo para cima e eu não posso vê-lo
Saifan Nadaf

18

Não é um anúncio, promoção ou spam , apenas uma boa solução. Sei que esta pergunta tem quase 30 respostas e estou tão chocado que ninguém sequer mencionou uma vez sobre esse belo projeto do GitHub que faz tudo por você e ainda melhor. Todas as respostas apenas movem a visualização para cima. Acabei de resolver todos os meus problemas com este IQKeyboardManager. Tem mais de 13000 estrelas.
Basta adicionar isso no seu podfile se você estiver usando o swift

pod 'IQKeyboardManagerSwift'

e depois dentro do seu AppDelegate.swift faça import IQKeyboardManagerSwift

import IQKeyboardManagerSwift

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

      IQKeyboardManager.shared.enable = true // just add this line

      return true
    }
}

Adicione a linha IQKeyboardManager.shared.enable = truepara habilitá-la
Esta solução é essencial se você estiver indo para produção.


Este é realmente bom, mas a versão mais recente não funciona para mim, eu usei 6.2.1, e importação como import IQKeyboardManagere usado IQKeyboardManager.shared().isEnabled = truena AppDelegate
Dhanu K

2
E isso funciona impressionante ao usar vários textos editar, Isto salvou o meu tempo
Dhanu K

1
Não posso agradecer o suficiente por apontar para esta maravilhosa biblioteca. Esta biblioteca é finalmente A RESPOSTA FINAL a todas as bobagens relacionadas ao teclado que a Apple nunca forneceu uma solução. Agora vou usá-lo para todos os meus projetos, novos e antigos, e economizar tempo e dor de cabeça com a aparição, desaparecimento ou não desse teclado, ou como ocultá-lo e por que está sobreposto, problemas me causam desde o dia eu estou programando para iPhones.
zeeshan

1
Eu havia escrito meu próprio código para mover o campo de texto, assim como as outras soluções aqui. Descobri que o IQKeyboardManager é muito bom e vou incorporá-lo a partir de agora. Manterá meu código acessível caso a estrutura não seja atualizada.
TM Lynch

@ DhanuK, Acabei de encontrar esta biblioteca e funciona perfeitamente e é fácil. O código de delegação do aplicativo foi atualizado para IQKeyboardManager.shared.enable = true
adougies

15

Para erro de tela preta (Swift 4 e 4.2) .

Corrigi o problema de tela preta. Na solução verificada A altura do teclado muda após tocar e isso está causando a tela preta.

É necessário usar UIKeyboardFrameEndUserInfoKey em vez de UIKeyboardFrameBeginUserInfoKey

var isKeyboardAppear = false

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

@objc func keyboardWillShow(notification: NSNotification) {
    if !isKeyboardAppear {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            if self.view.frame.origin.y == 0{
                self.view.frame.origin.y -= keyboardSize.height
            }
        }
        isKeyboardAppear = true
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    if isKeyboardAppear {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            if self.view.frame.origin.y != 0{
                self.view.frame.origin.y += keyboardSize.height
            }
        }
         isKeyboardAppear = false
    }
}

Não funcionará se houver uma barra de tabulação. Você precisa calcular a altura da barra de guias, caso contrário, haverá uma lacuna de tela preta entre o teclado e a visualização.
Ankur Lahiry

Isso não corrige a área preta onde o teclado estava no iPhone X e mais recente. E toda vez que o teclado aparece e desaparece, a tela principal continua deslizando para baixo.
Edison

14

Vejo que todas as respostas estão movendo a visualização em si pelo valor da altura do teclado. Bem, eu tenho uma resposta elaborada, que pode ser útil se você estiver usando restrições, ou sejaautolayout , , que move uma visualização alterando seu valor de restrição (restrições inferiores ou superiores, por exemplo) por um valor predefinido ou você pode usar o valor do tamanho do teclado.

Neste exemplo, eu uso a restrição inferior do campo de texto em Bottom Layout View com o valor inicial de 175.

@IBOutlet weak var bottomConstraint: NSLayoutConstraint!

override func viewDidLoad() {
    super.viewDidLoad()        
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil);
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil);
}

func keyboardWillShow(notification: NSNotification) {
    //To retrieve keyboard size, uncomment following line
    //let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()
    bottomConstraint.constant = 260
    UIView.animateWithDuration(0.3) {
        self.view.layoutIfNeeded()
    }
}

func keyboardWillHide(notification: NSNotification) {
    //To retrieve keyboard size, uncomment following line
    //let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()
    bottomConstraint.constant = 175
    UIView.animateWithDuration(0.3) {
        self.view.layoutIfNeeded()
    }
}

Oi senhor, você poderia me dizer por que isso não funciona quando colocado em uma exibição que também contém um TableView? Funciona bem no mesmo cenário quando contém um CollectionView.
Elarcoiris 18/10/19

9

Houve algumas mudanças na forma como definimos a KeyboardWillHideNotification.

Esta solução funciona com o Swift 4.2 :

NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)


@objc func keyboardWillShow(_ notification:Notification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        self.view.frame.origin.y -= keyboardSize.height
    }
}

@objc func keyboardWillHide(_ notification:Notification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        self.view.frame.origin.y += keyboardSize.height
    }
}

2
e se o meu campo de texto estiver no topo da exibição ..? Quero dizer, se existe um campo de texto com origem Y = 0 .. ?? depois textField está indo para cima e eu não posso vê-lo
Saifan Nadaf

7

Swift 5.0:

Após 4-5 horas de luta, eu vim com uma extensão simples do UIViewController com um código simples que funciona como charme

* A visualização não deve se mover quando o TextField estiver acima do teclado

* Não há necessidade de definir o valor constante como NSLayoutConstraint

* Nenhuma biblioteca de terceiros é necessária

* Não é necessário código de animação

* Funciona também em tableview

* Isso funciona em Layout automático / redimensionamento automático

extension UIViewController {
    func addKeyboardObserver() {
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardNotifications(notification:)),
                                               name: UIResponder.keyboardWillChangeFrameNotification,
                                               object: nil)
    }

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

    // This method will notify when keyboard appears/ dissapears
    @objc func keyboardNotifications(notification: NSNotification) {

        var txtFieldY : CGFloat = 0.0  //Using this we will calculate the selected textFields Y Position
        let spaceBetweenTxtFieldAndKeyboard : CGFloat = 5.0 //Specify the space between textfield and keyboard


        var frame = CGRect(x: 0, y: 0, width: 0, height: 0)
        if let activeTextField = UIResponder.currentFirst() as? UITextField ?? UIResponder.currentFirst() as? UITextView {
            // Here we will get accurate frame of textField which is selected if there are multiple textfields
            frame = self.view.convert(activeTextField.frame, from:activeTextField.superview)
            txtFieldY = frame.origin.y + frame.size.height
        }

        if let userInfo = notification.userInfo {
            // here we will get frame of keyBoard (i.e. x, y, width, height)
            let keyBoardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
            let keyBoardFrameY = keyBoardFrame!.origin.y
            let keyBoardFrameHeight = keyBoardFrame!.size.height

            var viewOriginY: CGFloat = 0.0
            //Check keyboards Y position and according to that move view up and down
            if keyBoardFrameY >= UIScreen.main.bounds.size.height {
                viewOriginY = 0.0
            } else {
                // if textfields y is greater than keyboards y then only move View to up
                if txtFieldY >= keyBoardFrameY {

                    viewOriginY = (txtFieldY - keyBoardFrameY) + spaceBetweenTxtFieldAndKeyboard

                    //This condition is just to check viewOriginY should not be greator than keyboard height
                    // if its more than keyboard height then there will be black space on the top of keyboard.
                    if viewOriginY > keyBoardFrameHeight { viewOriginY = keyBoardFrameHeight }
                }
            }

            //set the Y position of view
            self.view.frame.origin.y = -viewOriginY
        }
    }
}

Adicione esta extensão do UIResponder para obter qual TextField está selecionado

extension UIResponder {

    static weak var responder: UIResponder?

    static func currentFirst() -> UIResponder? {
        responder = nil
        UIApplication.shared.sendAction(#selector(trap), to: nil, from: nil, for: nil)
        return responder
    }

    @objc private func trap() {
        UIResponder.responder = self
    }
}

Em seguida, use isso em qualquer ViewController

   override func viewWillAppear(_ animated: Bool) {
        self.addKeyboardObserver()
    }

    override func viewWillDisappear(_ animated: Bool) {
        self.removeKeyboardObserver()
    }


Parecia a melhor solução, no entanto, existem alguns bugs. 1, o campo de texto se move para cima, mas quando começo a digitar, ele pula um pouco mais. 2, Em paisagem, ao digitar o campo de texto, às vezes pula para a esquerda.
Darren

@ Darren eu estou tentando descobrir esses bugs, mas eu não encontrei, você pode por favor dizer onde você conseguiu esses bugs, quero dizer para qual versão / dispositivo ... ??
Saifan Nadaf

6

Para o Swift 3, criei uma subclasse UIViewController, pois precisava de comportamento constante em todos os View Controllers.

class SomeClassVC: UIViewController {

  //MARK: - Lifecycle
  override func viewDidLoad() {
    super.viewDidLoad()

    addKeyboardObservers()
  }

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

    removeKeyboardObservers()
  }

  //MARK: - Overrides
  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    view.endEditing(true)
  }

  //MARK: - Help
  func addKeyboardObservers() {
    NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
  }

  func removeKeyboardObservers() {
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: self.view.window)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: self.view.window)
  }

  func keyboardWillShow(notification: NSNotification) {
    let keyboardHeight = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.height
    UIView.animate(withDuration: 0.1, animations: { () -> Void in
      self.view.window?.frame.origin.y = -1 * keyboardHeight!
      self.view.layoutIfNeeded()
    })
  }

  func keyboardWillHide(notification: NSNotification) {
    UIView.animate(withDuration: 0.1, animations: { () -> Void in
      self.view.window?.frame.origin.y = 0
      self.view.layoutIfNeeded()
    })
  }

  func resignTextFieldFirstResponders() {
    for textField in self.view.subviews where textField is UITextField {
      textField.resignFirstResponder()
    }
  }

  func resignAllFirstResponders() {
      view.endEditing(true)
  }
}

Inspirado na solução da Pavle, atualizei-o para aumentar automaticamente o teclado em uma determinada porcentagem do espaço disponível restante e também encontrar o campo focado recursivamente para o layout adequado. Agarre-o aqui: gist.github.com/noordawod/24d32b2ce8363627ea73d7e5991009a0
Noor Dawod

Minha barra de guias também está subindo com a janela! :(
Alfi

6

A resposta validada não leva em consideração a posição do campo de texto e apresenta algum erro (deslocamento duplo, nunca volte à posição primária, deslocamento mesmo que o campo texex esteja no topo da visualização ...)

A ideia é:

  • para obter o foco na posição Y absoluta do TextField
  • para obter a altura do teclado
  • para obter o ScreenHeight
  • Em seguida, calcule a distância entre a posição do teclado e o campo de texto (se <0 -> subir a exibição)
  • usar UIView.transform em vez de UIView.frame.origin.y - = .., faça com que seja mais fácil voltar à posição original com UIView.transform = .identity

então poderemos mover a visualização somente se necessário e o deslocamento específico para ter o texField focalizado logo acima do teclado

Aqui está o código:

Swift 4

class ViewController: UIViewController, UITextFieldDelegate {

var textFieldRealYPosition: CGFloat = 0.0

override func viewDidLoad() {
    super.viewDidLoad()

    NotificationCenter.default.addObserver(self, selector: #selector(VehiculeViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(VehiculeViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)

  // Delegate all textfields

}


@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        let distanceBetweenTextfielAndKeyboard = self.view.frame.height - textFieldRealYPosition - keyboardSize.height
        if distanceBetweenTextfielAndKeyboard < 0 {
            UIView.animate(withDuration: 0.4) {
                self.view.transform = CGAffineTransform(translationX: 0.0, y: distanceBetweenTextfielAndKeyboard)
            }
        }
    }
}


@objc func keyboardWillHide(notification: NSNotification) {
    UIView.animate(withDuration: 0.4) {
        self.view.transform = .identity
    }
}


func textFieldDidBeginEditing(_ textField: UITextField) {
  textFieldRealYPosition = textField.frame.origin.y + textField.frame.height
  //take in account all superviews from textfield and potential contentOffset if you are using tableview to calculate the real position
}

}


Muito bom! (Em viewDidLoad, você tem "VeículoVisualizadorControlador" em vez de apenas "VeioVisualizador").
Rene6 /

Uma resposta muito mais completa e útil. Obrigado! Sugiro que a verificação do teclado seja chamada da seguinte maneira, pois fornecerá um tamanho consistente do teclado ......... se for permitido keyboardSize = (notification.userInfo? [UIResponder.keyboardFrameEndUserInfoKey] como? NSValue) ?. cgRectValue .size
Ben

4

Percebi que as outras respostas envolviam cortar parte da parte superior da vista. Se você deseja redimensionar a visualização sem cortar nenhum conteúdo, tente este método :)

func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.setTranslatesAutoresizingMaskIntoConstraints(true)
        self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.height - keyboardSize.height)
    }
}

func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.collectionView.setTranslatesAutoresizingMaskIntoConstraints(false)
        self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.height + keyboardSize.height)
    }
}

4

Meus dois centavos para iniciantes: nas amostras acima, alguém altera as coordenadas, outros usa a "máscara de redimensionamento automático" e outras restrições:

Como a Apple diz, não misture esses três tipos de lógica. Se você tiver restrições no Storyboard, não tente alterar x / y. Definitivamente não funciona.


4

Portanto, nenhuma das outras respostas parece acertar.

O teclado com bom comportamento no iOS deve:

  • Redimensionar automaticamente quando o teclado mudar de tamanho (SIM, PODE)
  • Animar na mesma velocidade que o teclado
  • Animar usando a mesma curva do teclado
  • Respeite as áreas seguras, se relevante.
  • Também funciona no modo iPad / Desacoplado

Meu código usa um NSLayoutConstraintdeclarado como um@IBOutlet

@IBOutlet private var bottomLayoutConstraint: NSLayoutConstraint!

Você também pode usar transformações, visualizar desvios, .... Eu acho que é mais fácil com a restrição tho. Ele funciona definindo uma restrição na parte inferior; talvez seja necessário alterar o código se sua constante não for 0 / Não na parte inferior.

Aqui está o código:

// In ViewDidLoad
    NotificationCenter.default.addObserver(self, selector: #selector(?MyViewController.keyboardDidChange), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)


@objc func keyboardDidChange(notification: Notification) {
    let userInfo = notification.userInfo! as [AnyHashable: Any]
    let endFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
    let animationDuration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber
    let animationCurve = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as! NSNumber
    bottomLayoutConstraint.constant = view.frame.height - endFrame.origin.y - view.safeAreaInsets.bottom // If your constraint is not defined as a safeArea constraint you might want to skip the last part.
    // Prevents iPad undocked keyboard.
    guard endFrame.height != 0, view.frame.height == endFrame.height + endFrame.origin.y else {
        bottomLayoutConstraint.constant = 0
        return
    }
    UIView.setAnimationCurve(UIView.AnimationCurve(rawValue: animationCurve.intValue)!)
    UIView.animate(withDuration: animationDuration.doubleValue) {
        self.view.layoutIfNeeded()
        // Do additional tasks such as scrolling in a UICollectionView
    }
}

3

sua resposta 100% perfeita para todas as atualizações do Guy Altura da tableview quando o teclado está aberto

Para Swift4.2

   override func viewDidLoad() {
      super.viewDidLoad()
      NotificationCenter.default.addObserver(self, selector: #selector(RecipeVC.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)

      NotificationCenter.default.addObserver(self, selector: #selector(RecipeVC.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
   }

   @objc func keyboardWillShow(notification: NSNotification) {
    if ((notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {

        var userInfo = notification.userInfo!
        var keyboardFrame:CGRect = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
        keyboardFrame = self.view.convert(keyboardFrame, from: nil)

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

   @objc func keyboardWillHide(notification: NSNotification) {
    if ((notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue) != nil {
        let contentInset:UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        self.tbl.contentInset = contentInset
    }
}

Swift3.2

    override func viewDidLoad() {
          super.viewDidLoad()

           NotificationCenter.default.addObserver(self, selector: #selector(RecipeVC.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)

           NotificationCenter.default.addObserver(self, selector: #selector(RecipeVC.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }
    func keyboardWillShow(notification: NSNotification) {
         if ((notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {
         //self.view.frame.origin.y -= keyboardSize.height
         var userInfo = notification.userInfo!
         var keyboardFrame:CGRect = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
          keyboardFrame = self.view.convert(keyboardFrame, from: nil)

          var contentInset:UIEdgeInsets = self.tbl.contentInset
          contentInset.bottom = keyboardFrame.size.height
          self.tbl.contentInset = contentInset

       }
    }

    func keyboardWillHide(notification: NSNotification) {
         if ((notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue) != nil {
         let contentInset:UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
         self.tbl.contentInset = contentInset
         }
    }

Esta é a melhor resposta. TBL deve ser tableView e eu adicionei alguns padding: contentInset.bottom = keyboardFrame.size.height + 10
iphaaw

2

Para Swift 3

func textFieldDidBeginEditing(_ textField: UITextField) { // became first responder

    //move textfields up
    let myScreenRect: CGRect = UIScreen.main.bounds
    let keyboardHeight : CGFloat = 216

    UIView.beginAnimations( "animateView", context: nil)
    var movementDuration:TimeInterval = 0.35
    var needToMove: CGFloat = 0

    var frame : CGRect = self.view.frame
    if (textField.frame.origin.y + textField.frame.size.height + UIApplication.shared.statusBarFrame.size.height > (myScreenRect.size.height - keyboardHeight - 30)) {
        needToMove = (textField.frame.origin.y + textField.frame.size.height + UIApplication.shared.statusBarFrame.size.height) - (myScreenRect.size.height - keyboardHeight - 30);
    }

    frame.origin.y = -needToMove
    self.view.frame = frame
    UIView.commitAnimations()
}

func textFieldDidEndEditing(_ textField: UITextField) {
    //move textfields back down
    UIView.beginAnimations( "animateView", context: nil)
    var movementDuration:TimeInterval = 0.35
    var frame : CGRect = self.view.frame
    frame.origin.y = 0
    self.view.frame = frame
    UIView.commitAnimations()
}

2

Swift 4:

Eu estava tendo um problema com a resposta mais aceita, na qual ocultar o teclado não retornou a exibição até o final da página (apenas parcialmente). Isso funcionou para mim (+ atualizado para o Swift 4).

override func viewDidLoad() {
    super.viewDidLoad()
    self.hideKeyboardWhenTappedAround()
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0{
            self.view.frame.origin.y -= keyboardSize.height
        }
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y != 0{
            self.view.frame.origin.y = 0
        }
    }
}

e se o meu campo de texto estiver no topo da exibição ..? Quero dizer, se existe um campo de texto com origem Y = 0 .. ?? depois textField está indo para cima e eu não posso vê-lo
Saifan Nadaf

2

Semelhante à resposta @Boris, mas no Swift 5 :

override func viewDidLoad() {
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}

@IBAction func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }
}

@IBAction func keyboardWillHide(notification: NSNotification) {
    if self.view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}

1

Aqui está minha solução (na verdade, esse código é para o caso em que você tem poucos campos de texto em sua exibição, isso também funciona para o caso em que você possui um campo de texto)

class MyViewController: UIViewController, UITextFieldDelegate {

@IBOutlet weak var firstTextField: UITextField!
@IBOutlet weak var secondTextField: UITextField!

var activeTextField: UITextField!
var viewWasMoved: Bool = false


override func viewDidLoad() {
    super.viewDidLoad()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PrintViewController.keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PrintViewController.keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil)
}

override func viewDidDisappear(animated: Bool) {
    super.viewWillDisappear(animated)
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

func textFieldDidBeginEditing(textField: UITextField) {
    self.activeTextField = textField
}

func textFieldDidEndEditing(textField: UITextField) {
    self.activeTextField = nil
}

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


func keyboardWillShow(notification: NSNotification) {

    let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()

    var aRect: CGRect = self.view.frame
    aRect.size.height -= keyboardSize!.height

    let activeTextFieldRect: CGRect? = activeTextField?.frame
    let activeTextFieldOrigin: CGPoint? = activeTextFieldRect?.origin

    if (!CGRectContainsPoint(aRect, activeTextFieldOrigin!)) {
        self.viewWasMoved = true
        self.view.frame.origin.y -= keyboardSize!.height
    } else {
        self.viewWasMoved = false
    }
}

func keyboardWillHide(notification: NSNotification) {
    if (self.viewWasMoved) {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            self.view.frame.origin.y += keyboardSize.height
        }
    }
}

Não se esqueça de definir o delegado para os campos de texto
SwingerDinger

Alterar a condição em keyboardwillshow como, se (CGRectContainsPoint (aRect, newOrgin) && self.viewWasMoved!)
KingofBliss

adicionar self.viewWasMoved = false quando u redefinir o quadro
KingofBliss

1

Atualizado para o Swift 3 ...

Como já foi dito, você precisa adicionar observadores de notificação no método viewDidLoad () do seu controlador, da seguinte maneira:

NotificationCenter.default.addObserver(forName: .UIKeyboardWillShow, object: nil, queue: nil)
    { notification in
    self.keyboardWillShow(notification)
    }

NotificationCenter.default.addObserver(forName: .UIKeyboardWillHide, object: nil, queue: nil)
    { notification in
    self.keyboardWillHide(notification)
    }

NotificationCenter.default.addObserver(forName: .UIKeyboardDidShow, object: nil, queue: nil)
    { _ in
    self.enableUserInteraction()
    }

NotificationCenter.default.addObserver(forName: .UIKeyboardDidHide, object: nil, queue: nil)
    { _ in
    self.enableUserInteraction()
    }

Lembre-se de remover seus observadores quando apropriado (eu faço isso no método viewWillDisappear ())

NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardDidShow, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardDidHide, object: nil)

Em seguida, implemente os métodos show e hide - observe a linha que instrui o aplicativo a ignorar os eventos de interação (beginIgnoringInteractionEvents). Isso é importante, pois sem ele, o usuário pode tocar em um campo ou até mesmo em uma visualização de rolagem e fazer com que a mudança ocorra uma segunda vez, resultando em uma terrível falha na interface do usuário. Ignorar eventos de interação anteriores à exibição e ocultação do teclado impedirá isso:

func keyboardWillShow(notification: Notification)
    {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
        {
        UIApplication.shared.beginIgnoringInteractionEvents()
        self.view.frame.origin.y -= keyboardSize.height
        // add this line if you are shifting a scrollView, as in a chat application
        self.timelineCollectionView.contentInset.top += keyboardSize.height
        }
    }

func keyboardWillHide(notification: Notification)
    {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
        {
        UIApplication.shared.beginIgnoringInteractionEvents()
        self.view.frame.origin.y += keyboardSize.height
        // add this line if you are shifting a scrollView, as in a chat application
        self.timelineCollectionView.contentInset.top -= keyboardSize.height
        }
    }

Por fim, reative as interações do usuário (lembre-se, este método é acionado após o teclado didShow ou didHide):

func enableUserInteraction()
    {
    UIApplication.shared.endIgnoringInteractionEvents()
    }

1

Código Swift 3

var activeField: UITextField?

override func viewDidLoad() {
    super.viewDidLoad()

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

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

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

func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if (self.activeField?.frame.origin.y)! >= keyboardSize.height {
            self.view.frame.origin.y = keyboardSize.height - (self.activeField?.frame.origin.y)!
        } else {
            self.view.frame.origin.y = 0
        }
    }
}

func keyboardWillHide(notification: NSNotification) {
    self.view.frame.origin.y = 0
}

1

Se você possui 2 ou mais campos de texto no mesmo VC e o usuário toca em um deles e depois no outro, sem chamar a função keyboardWillHide, a visualização está subindo mais uma vez, o que não é necessário, porque você terá o teclado, um espaço em branco com a altura do teclado e a visualização, usando o código na resposta que editei:

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

func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.frame.origin.y -= keyboardSize.height
    }
}

func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.frame.origin.y += keyboardSize.height
    }
}

Para resolver isso, substitua as duas funções "KeyboardWillShow / Hide" por estas:

func keyboardWillShow(notification: NSNotification) {
 if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
    if view.frame.origin.y == 0{
        self.view.frame.origin.y -= keyboardSize.height
        }
    }
}

func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        if view.frame.origin.y != 0 {
            self.view.frame.origin.y += keyboardSize.height
        }
    }
}

e se o meu textField estiver no topo da visualização ..? Quero dizer, se existe um campo de texto com origem Y = 0 .. ?? então o textField está subindo e eu não consigo ver #
Saifan Nadaf

1

A solução do @ Boris é MUITO boa, mas a visualização às vezes pode ser corrompida.

Para o alinhamento perfeito, use o código abaixo

override func viewDidLoad() {
super.viewDidLoad()            
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)}

Funções:

@objc func keyboardWillShow(notification: NSNotification) {        
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
    if self.view.frame.origin.y == 0{
        self.view.frame.origin.y -= keyboardSize.height
    }
}}    

E,

@objc func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
    if self.view.frame.origin.y != 0{
        self.view.frame.origin.y = 0 
    }
} }

0

este tutorial em vídeo é o melhor. 7 minutos e isso fará muito sentido. Uma solução tão simples para quando você tem vários campos de texto e deseja que a exibição de rolagem mova a quantidade "x" de pixels quando esse campo de texto específico é tocado.

https://youtu.be/VuiPGJOEBH4

Apenas estas etapas:

Coloque todos os seus campos de texto em uma visualização de rolagem restrita às bordas da visualização.

-Conecte todos os campos de texto e role a exibição como delegados ao controlador de exibição.

-Conecte todos os campos de texto e role a exibição com um IBOutlet.

class ViewController: UIViewController, UITextFieldDelegate {

-Adicione o protocolo UITextFieldDelegate à sua classe

@IBOutlet var stateAddress: UITextField!
@IBOutlet var zipAddress: UITextField!
@IBOutlet var phoneNumber: UITextField!
@IBOutlet var vetEmailAddress: UITextField!    
@IBOutlet weak var scrollView: UIScrollView!

-Adicione métodos UITextFieldDelegate ao seu arquivo rápido:

func textFieldShouldReturn(textField: UITextField) -> Bool {

    textField.resignFirstResponder()
    return true
}


func textFieldDidBeginEditing(textField: UITextField) {

    if (textField == self.stateAddress) {
        scrollView.setContentOffset(CGPointMake(0, 25), animated: true)
    }
    else if (textField == self.zipAddress) {
        scrollView.setContentOffset(CGPointMake(0, 57), animated: true)
    }
    else if (textField == self.phoneNumber) {
        scrollView.setContentOffset(CGPointMake(0, 112), animated: true)
    }
    else if (textField == self.vetEmailAddress) {
        scrollView.setContentOffset(CGPointMake(0, 142), animated: true)
    }
}

func textFieldDidEndEditing(textField: UITextField) {

    scrollView.setContentOffset(CGPointMake(0, 0), animated: true)
}

O primeiro método apenas ativa o botão de retorno no teclado para dispensá-lo. A segunda é quando você toca em qualquer campo de texto específico e, em seguida, define o deslocamento y da distância percorrida pelo scrollview (o meu se baseia na localização y dos controladores de vista 25,57,112,142). O último diz que quando você toca fora do teclado, a visualização de rolagem volta ao local original.

Eu fiz meu pixel de visualização perfeito dessa maneira!


0

Esse shud de recurso foi criado no Ios, no entanto, precisamos fazer isso externamente.
Insira o código abaixo
* Para mover a visualização quando o campo de texto estiver sob o teclado,
* Para não mover a visualização quando o campo de texto estiver acima do teclado
* Para mover a Visualização com base na altura do teclado, quando necessário.
Isso funciona e testado em todos os casos.

import UIKit

class NamVcc: UIViewController, UITextFieldDelegate
{
    @IBOutlet weak var NamTxtBoxVid: UITextField!

    var VydTxtBoxVar: UITextField!
    var ChkKeyPadDspVar: Bool = false
    var KeyPadHytVal: CGFloat!

    override func viewDidLoad()
    {
        super.viewDidLoad()

        NamTxtBoxVid.delegate = self
    }

    override func viewWillAppear(animated: Bool)
    {
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: #selector(TdoWenKeyPadVyd(_:)),
            name:UIKeyboardWillShowNotification,
            object: nil);
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: #selector(TdoWenKeyPadHyd(_:)),
            name:UIKeyboardWillHideNotification,
            object: nil);
    }

    func textFieldDidBeginEditing(TxtBoxPsgVar: UITextField)
    {
        self.VydTxtBoxVar = TxtBoxPsgVar
    }

    func textFieldDidEndEditing(TxtBoxPsgVar: UITextField)
    {
        self.VydTxtBoxVar = nil
    }

    func textFieldShouldReturn(TxtBoxPsgVar: UITextField) -> Bool
    {
        self.VydTxtBoxVar.resignFirstResponder()
        return true
    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
    {
        view.endEditing(true)
        super.touchesBegan(touches, withEvent: event)
    }

    func TdoWenKeyPadVyd(NfnPsgVar: NSNotification)
    {
        if(!self.ChkKeyPadDspVar)
        {
            self.KeyPadHytVal = (NfnPsgVar.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().height

            var NonKeyPadAraVar: CGRect = self.view.frame
            NonKeyPadAraVar.size.height -= self.KeyPadHytVal

            let VydTxtBoxCenVal: CGPoint? = VydTxtBoxVar?.frame.origin

            if (!CGRectContainsPoint(NonKeyPadAraVar, VydTxtBoxCenVal!))
            {
                self.ChkKeyPadDspVar = true
                UIView.animateWithDuration(1.0,
                    animations:
                    { self.view.frame.origin.y -= (self.KeyPadHytVal)},
                    completion: nil)
            }
            else
            {
                self.ChkKeyPadDspVar = false
            }
        }

    }

    func TdoWenKeyPadHyd(NfnPsgVar: NSNotification)
    {
        if (self.ChkKeyPadDspVar)
        {
            self.ChkKeyPadDspVar = false
            UIView.animateWithDuration(1.0,
                animations:
                { self.view.frame.origin.y += (self.KeyPadHytVal)},
                completion: nil)
        }
    }

    override func viewDidDisappear(animated: Bool)
    {
        super.viewWillDisappear(animated)
        NSNotificationCenter.defaultCenter().removeObserver(self)
        view.endEditing(true)
        ChkKeyPadDspVar = false
    }
}

| :: | Às vezes, o modo de exibição será desativado. Nesse caso, use a altura +/- 150:

    NonKeyPadAraVar.size.height -= self.KeyPadHytVal + 150

    { self.view.frame.origin.y -= self.KeyPadHytVal  - 150},
                    completion: nil)

    { self.view.frame.origin.y += self.KeyPadHytVal  - 150},
                completion: nil)

0
func keyboardWillShow(notification: NSNotification) {

    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.frame.origin.y = self.view.frame.height - (self.view.frame.height + keyboardSize.height)
    }

}

func keyboardWillHide(notification: NSNotification) {
        self.view.frame.origin.y = 0
}

deve ser mais estável


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

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

 }

 // MARK: - keyboard
 func keyboardWillShow(notification: NSNotification) 
{

if let userInfo = notification.userInfo {
if let keyboardSize = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
let contentInsets = self.tblView.contentInset as UIEdgeInsets
self.tblView.contentInset = UIEdgeInsets(top: contentInsets.top, left: contentInsets.left, bottom: keyboardSize.height, right:contentInsets.right)
                    // ...
                } else {
                    // no UIKeyboardFrameBeginUserInfoKey entry in userInfo
                }
            } else {
                // no userInfo dictionary in notification
            }
        }

func keyboardWillHide(notification: NSNotification) 
{
let contentInsets = self.tblView.contentInset as UIEdgeInsets
self.tblView.contentInset = UIEdgeInsets(top: contentInsets.top, left: contentInsets.left, bottom: 0, right:contentInsets.right)
 }

0

Use o código a seguir para visualizar Up on UITextField Clicked

func textFieldDidBeginEditing(textField: UITextField) {
    ViewUpanimateMoving(true, upValue: 100)
}
func textFieldDidEndEditing(textField: UITextField) {
    ViewUpanimateMoving(false, upValue: 100)
}
func ViewUpanimateMoving (up:Bool, upValue :CGFloat){
    var durationMovement:NSTimeInterval = 0.3
    var movement:CGFloat = ( up ? -upValue : upValue)
    UIView.beginAnimations( "animateView", context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(durationMovement)
    self.view.frame = CGRectOffset(self.view.frame, 0,  movement)
    UIView.commitAnimations()
}

0

Fiz um cocoapod para simplificar o assunto:

https://github.com/xtrinch/KeyboardLayoutHelper

Como usá-lo:

Faça uma restrição inferior de layout automático, atribua a ele uma classe de KeyboardLayoutConstraint no módulo KeyboardLayoutHelper e o pod fará o trabalho necessário para aumentá-lo para acomodar o teclado que aparece e desaparece. Veja exemplos de projetos em exemplos de como usá-lo (fiz dois: textFields dentro de um scrollView e textFields centralizados verticalmente com duas visualizações básicas - logon e registro).

A restrição de layout inferior pode ser a visualização do contêiner, o próprio campo de texto, qualquer coisa, qualquer que seja o nome.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.