Alinhe programaticamente uma barra de ferramentas na parte superior do teclado do iPhone

94

Em vários casos, desejo adicionar uma barra de ferramentas na parte superior do teclado do iPhone (como no iPhone Safari quando você está navegando em elementos de formulário, por exemplo).

Atualmente, estou especificando o retângulo da barra de ferramentas com constantes, mas porque outros elementos da interface estão em fluxo - barras de ferramentas e barras de navegação no topo da tela - toda vez que fazemos uma pequena alteração na interface, a barra de ferramentas sai do alinhamento.

Existe uma maneira de determinar programaticamente a posição do teclado em relação à visualização atual?

Rob Drimmie
fonte

Respostas:

142

A partir do iOS 3.2, há uma nova maneira de obter esse efeito:

UITextFieldse UITextViewstem uma inputAccessoryViewpropriedade, que você pode definir para qualquer visualização, que é automaticamente exibida acima e animada com o teclado.

Observe que a visualização que você usa não deve estar na hierarquia de visualizações em nenhum outro lugar, nem deve ser adicionada a alguma supervisão, isso é feito para você.

Tonklon
fonte
deixe-me tentar . Embora pareça a melhor maneira.
harshalb
Uau. Que achado! Obrigado (eu fiz da maneira mais difícil e é uma bagunça)
levous
1
Eu tenho um UIToolbar com um UITextField dentro de um de seus itens de botão da barra, mas embora eu tenha definido textFields inputAccessoryView para essa barra de ferramentas na primeira vez que a barra de ferramentas sobe, mas nenhum teclado aparece. No segundo toque o teclado aparece com a barra de ferramentas tem alguma ideia sobre isso?
Ugur Kumru
Mas como adicionar uma barra de ferramentas no UIWebView? :(
Dmitry
Eu fiz isso substituindo os botões na barra de ferramentas UIWebView padrão (o mesmo código para removê-la).
Dmitry
72

Então, basicamente:

No método init:

NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(keyboardWillShow:) name: UIKeyboardWillShowNotification object:nil];
[nc addObserver:self selector:@selector(keyboardWillHide:) name: UIKeyboardWillHideNotification object:nil];

E, em seguida, tenha os métodos mencionados acima para ajustar a posição da barra:

-(void) keyboardWillShow:(NSNotification *) note
{
    CGRect r  = bar.frame, t;
    [[note.userInfo valueForKey:UIKeyboardBoundsUserInfoKey] getValue: &t];
    r.origin.y -=  t.size.height;
    bar.frame = r;
}

Pode torná-lo bonito, animando a mudança de posição, envolvendo-o em

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.3];
//...
    [UIView commitAnimations];

fonte
Estava vasculhando minhas coisas antigas esta manhã e percebi que esta é uma resposta muito melhor e mais abrangente. Obrigado!
Rob Drimmie
Essa resposta ainda é bastante relevante um ano depois. Isso me ajudou a superar o obstáculo ao desenvolver algo relacionado a isso.
james_womack
2
Apenas um aviso para as pessoas que estão se deparando com esta questão agora: o UIKeyboardBoundsUserInfoKey agora está obsoleto no iPhone OS 3.2. Existem outros semelhantes, como os UIKeyboardFrameBeginUserInfoKeyque fornecem as mesmas informações.
Stephen Darlington
9
Existe ainda uma nova maneira melhor de fazer isso no iOS3.2, a propriedade inputAccessoryView em UITextField e UITextView.
tonklon
6
Essa resposta ajudou muito, mas é um pouco desatualizada. Você deve usar UIKeyboardFrameEndUserInfoKeypara obter o quadro final (em coordenadas de tela) do teclado. Você também pode usar UIKeyboardAnimationDurationUserInfoKeye UIKeyboardAnimationCurveUserInfoKeypara obter o resto dos parâmetros de que precisa para corresponder exatamente ao comportamento do teclado.
Dave Peck
60

Isso se baseia na resposta existente do tonklon - estou apenas adicionando um trecho de código que mostra uma barra de ferramentas preta semitransparente na parte superior do teclado, junto com um botão "pronto" à direita:

UIToolbar *toolbar = [[[UIToolbar alloc] init] autorelease];
[toolbar setBarStyle:UIBarStyleBlackTranslucent];
[toolbar sizeToFit];

UIBarButtonItem *flexButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
UIBarButtonItem *doneButton =[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(resignKeyboard)];

NSArray *itemsArray = [NSArray arrayWithObjects:flexButton, doneButton, nil];

[flexButton release];
[doneButton release];
[toolbar setItems:itemsArray];

[aTextField setInputAccessoryView:toolbar];

e se -resignKeyboardparece com:

-(void)resignKeyboard {
  [aTextField resignFirstResponder];
}

Espero que ajude alguém.

phi
fonte
2
Apenas adicionando um pequeno comentário sobre como colocar o próximo anterior no lugar. UISegmentedControl * segmentControl = [[UISegmentedControl alloc] initWithItems: [NSArray arrayWithObjects: @ "Anterior", @ "Próximo", nulo]]; [segmentControl setSegmentedControlStyle: UISegmentedControlStyleBar]; [segmentControl addTarget: ação própria: @selector (nextPrevious :) forControlEvents: UIControlEventValueChanged];
Trausti Thor
1
Uma adição ao comentário de @TraustiThor: você tem que envolver o controle segmentado em um UIBarButtonItem para adicioná-lo à barra de ferramentas.
Tim Büthe de
Excelente - esse é todo o código de que eu precisava. Obrigado por postar :)
Estique
Mas e quanto ao UIWebView? Como adicionar uma barra de ferramentas a ele?
Dmitry
24

Se você se registrar para notificações de teclado, ou seja UIKeyboardWillShowNotification UIKeyboardWillHideNotification, etc, a notificação que você receberá conterá os limites do teclado no userInfodict ( UIKeyboardBoundsUserInfoKey).

Veja a UIWindowreferência da classe.

amrox
fonte
16

No 3.0 e superior, você pode obter a duração e a curva da animação do userInfodicionário de notificações.

por exemplo, para animar o tamanho da visualização para abrir espaço para o teclado, registre-se no UIKeyboardWillShowNotificatione faça algo como o seguinte:

- (void)keyboardWillShow:(NSNotification *)notification
{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
    [UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];

    CGRect frame = self.view.frame;
    frame.size.height -= [[[notification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey] CGRectValue].size.height;
    self.view.frame = frame;

    [UIView commitAnimations];
}

Faça uma animação semelhante para UIKeyboardWillHideNotification.

David Beck
fonte
Parece uma maneira melhor de fazer isso no 3.0 SDK, obrigado por postar!
Hua-Ying
Obrigado pelo código. Isso ajuda muito. Mas quando eu defino meu UITextView para se tornar o primeiro a responder no viewDidLoad, o UIToolBar não se move com o redimensionamento do self.view. Tens alguma ideia do porquê?
RyanJM
1
@RyanJM: BecomeFirstResponder e resignFirstResponder têm um comportamento estranho quando a visualização está fora da tela. Em vez disso, você deve chamar tornou-seFirstResponder a partir do método viewWillAppear.
David Beck
0

Crie este método e chame-o em ViewWillLoad:

        - (void) keyboardToolbarSetup
{
    if(self.keyboardToolbar==nil)
        {
        self.keyboardToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 44)];

        UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:@"Cancel" style:UIBarButtonItemStylePlain target:self action:@selector(anyAction)];

        UIBarButtonItem *extraSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];

        UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(anyOtherAction)];


        NSArray *toolbarButtons = [[NSArray alloc]initWithObjects:cancelButton,extraSpace,doneButton, nil];

        [self.keyboardToolbar setItems:toolbarButtons];

        self.myTextView.inputAccessoryView=self.keyboardToolbar;
        }
}
Juan Sebastián López
fonte
-3

Não há como (AFAIK) obter as dimensões da visualização do teclado. No entanto, é constante, pelo menos em todas as versões do iPhone até agora.

Se você calcular a posição da barra de ferramentas como um deslocamento da parte inferior da sua visualização e levar em consideração o tamanho da sua visualização, não deverá se preocupar se uma barra de navegação está presente ou não.

Por exemplo

#define KEYBOARD_HEIGHT 240 // example - can't remember the exact size
#define TOOLBAR_HEIGHT 30

toolBarRect.origin.y = viewRect.size.height - KEYBOARD_HEIGHT - TOOLBAR_HEIGHT;

// move toolbar either directly or with an animation

Em vez de definir, você pode criar facilmente uma keyboardHeightfunção que retorna o tamanho com base no fato de o teclado estar sendo exibido e mover o posicionamento da barra de ferramentas para uma função separada que reorganiza seu layout.

Também pode depender de onde você faz esse posicionamento, pois é possível que o tamanho da sua visualização possa mudar entre ser carregado e mostrado com base na configuração da sua barra de navegação. Acredito que o melhor lugar para fazer isso seria em viewWillAppear.

Andrew Grant
fonte
Funcionou muito bem, obrigado! Até agora tenho feito esse cálculo no seletor disparado por UIKeyboardDidShowNotification. Eu testei apenas em alguns lugares, mas parece um bom local.
Rob Drimmie,
A partir do 5.0, o tamanho do teclado não é mais estático.
Alastair Stuart