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.

Alex Catchpole
fonte
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
    }
}
Boris
fonte
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.

gammachill
fonte
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)
}
Dan Beaulieu
fonte
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
}
user3677173
fonte
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)
}
Scipianne
fonte
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.

weegee
fonte
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
    }
}
Ali Ihsan URAL
fonte
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()
    }
}
Amro Shafie
fonte
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
    }
}
Ivan Le Hjelmeland
fonte
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()
    }

Saifan Nadaf
fonte
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)
  }
}
Pavle Mijatovic
fonte
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
}

}

Quentin N
fonte
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)
    }
}
Grant Park
fonte
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.

ingconti
fonte
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
    }
}
Antzi
fonte
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
         }
    }
Maulik Patel
fonte
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()
}
Celil Bozkurt
fonte
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
        }
    }
}
Rbar
fonte
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
    }
}
Jerry Chong
fonte
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
        }
    }
}
Vah.Sah
fonte
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()
    }
Gene Loparco
fonte
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
}
Rohit Sharma
fonte
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
        }
    }
}
Mr. Xcoder
fonte
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 
    }
} }
Eray Alparslan
fonte
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!

bme003
fonte
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)
Sujay UN
fonte
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

Hadevs Play
fonte
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)
 }
Himali Shah
fonte
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()
}
Jugal K Balara
fonte
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.

xtrinch
fonte