以编程方式将工具栏与iPhone键盘顶部对齐

94

在一些情况下,我想添加一个工具栏到iPhone键盘的顶部(例如在iPhone Safari中导航表单元素时)。

目前,我正在使用常量指定工具栏的矩形框架,但由于界面的其他元素处于不稳定状态 - 例如屏幕顶部的工具栏和导航栏 - 每当我们进行轻微的界面更改时,工具栏就会失去对齐。

有没有办法通过编程确定键盘与当前视图的位置关系?

7个回答

141

从iOS 3.2开始,有一种新的实现方式:

UITextFieldsUITextViews 有一个名为 inputAccessoryView 的属性,您可以将其设置为任何视图,该视图会自动显示在键盘上方,并随键盘动画而移动。

请注意,您使用的视图既不应该在其他地方的视图层次结构中,也不应该将其添加到某个父视图,因为这些都已经由系统为您处理好了。


让我试试。虽然看起来是最好的方法。 - harshalb
哇,这真是太棒了!谢谢(我用了一种较困难的方式,结果看起来有些凌乱)。 - levous
1
我有一个UIToolbar,其中包含一个UITextField作为其一个bar button item的一部分,但是尽管我将textFields inputAccessoryView设置为该工具栏,在第一次按下时,工具栏会上移,但没有键盘出现。在第二次按下时,键盘出现并且工具栏也出现了。你对此有什么想法吗? - Ugur Kumru
但是如何在UIWebView上添加工具栏?:( - Dmitry
我已经通过替换标准UIWebView工具栏上的按钮(与删除它的相同代码)来完成了它。 - Dmitry
当键盘显示时,视图将从其父视图中移除,因此在某些情况下将其添加到其他视图是安全的,甚至是必需的,例如:当视图将自身设置为辅助视图 [myView setInputAccessoryView:myView]; - valexa

72
基本上来说:
在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];

接下来有上面提到的方法来调整工具栏的位置:

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

可以通过将其包装在动画中以使位置更改变得漂亮。

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

今天早上我在翻看我的旧东西时发现这是一个更好的、最全面的答案。谢谢! - Rob Drimmie
一年多以后,这个答案仍然非常相关。它帮助我克服了开发与之相关的某些东西时遇到的困难。 - james_womack
2
对于现在遇到这个问题的人,只是一个警告:UIKeyboardBoundsUserInfoKey在iPhone OS 3.2中已经被弃用。还有其他类似的键,比如UIKeyboardFrameBeginUserInfoKey,可以提供相同的信息。 - Stephen Darlington
9
在iOS 3.2中,UITextField和UITextView上有一种更好的新方法来实现这一点,即使用inputAccessoryView属性。 - tonklon
6
这个答案非常有用,但是有点过时了。你应该使用UIKeyboardFrameEndUserInfoKey来获取键盘的最终框架(以屏幕坐标为单位)。您还可以使用 UIKeyboardAnimationDurationUserInfoKeyUIKeyboardAnimationCurveUserInfoKey 来获取其余参数,以完全匹配键盘的行为。 - Dave Peck

60

这是基于tonklon的现有答案,我只是添加了一个代码片段,它显示了一个半透明黑色的工具栏在键盘上方,并带有一个位于右侧的“完成”按钮:

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

-resignKeyboard看起来像:

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

2
只是在获取下一个/上一个的位置上添加了一点注释。 UISegmentedControl *segmentControl = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:@"上一个", @"下一个", nil]]; [segmentControl setSegmentedControlStyle:UISegmentedControlStyleBar]; [segmentControl addTarget:self action:@selector(nextPrevious:) forControlEvents:UIControlEventValueChanged]; - Trausti Thor
1
@TraustiThor的评论中还有一个补充:您必须将分段控件包装在UIBarButtonItem中,以将其添加到工具栏中。 - Tim Büthe
太好了 - 这就是我需要的全部代码。感谢您的发布 :) - Stretch
但是UIWebView呢?如何为其添加工具栏? - Dmitry

24
如果您注册键盘通知,例如UIKeyboardWillShowNotificationUIKeyboardWillHideNotification,您将收到包含键盘边界的通知,它位于userInfo字典中 (UIKeyboardBoundsUserInfoKey)。
请参阅UIWindow类参考。

16
在3.0及以上版本中,您可以从通知的userInfo字典中获取动画持续时间和曲线。
例如,要对视图的大小进行动画处理以为键盘腾出空间,请注册UIKeyboardWillShowNotification并执行以下操作:
- (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];
}

针对 UIKeyboardWillHideNotification 进行类似的动画。


看起来在3.0 SDK上有更好的方法,感谢您的发布! - Hua-Ying
谢谢你的代码。这对我很有帮助。但是当我在viewDidLoad中将我的UITextView设置为第一响应者时,UIToolBar不会随着self.view的调整而移动。你有任何想法吗? - RyanJM
1
@RyanJM: 当视图不在屏幕上时,becomeFirstResponder和resignFirstResponder的行为很奇怪。你应该在viewWillAppear方法中调用becomeFirstResponder。 - David Beck

0
创建这个方法并在 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;
        }
}

-3

据我所知,没有办法获取键盘视图的尺寸。但是,至少在迄今为止的每个 iPhone 版本中,它是恒定的。

如果您将工具栏位置计算为从视图底部的偏移量,并考虑您的视图大小,则不必担心导航栏是否存在。

例如:

#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

你可以轻松地创建一个keyboardHeight函数来返回基于键盘是否正在显示的大小,而不是使用define,并将此工具栏定位移动到单独的函数中以重新组织布局。

此外,它可能取决于您执行此定位的位置,因为根据您的导航栏设置,您的视图的大小可能会在加载和显示之间发生变化。我认为最好的地方是在viewWillAppear中执行。


这个很好用,谢谢!到目前为止,我一直在UIKeyboardDidShowNotification触发的选择器中进行这个计算。虽然我只在几个地方测试过,但看起来是一个不错的位置。 - Rob Drimmie
从5.0版本开始,键盘大小不再是静态的。 - Alastair Stuart

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接