InputAccessoryView停靠在底部

我试图达到类似苹果的消息应用程序的底部文本input栏的定位行为。

我尝试了很多方法,search高低,有许多类似的问题,但没有一个是令人满意的。

要指定:

  1. 在视图的底部有一个UIToolbar
  2. 当键盘出现并消失时,工具栏将跟随键盘
  3. 当键盘可见时,工具栏应该保持在键盘的顶部
  4. 当键盘被隐藏时,工具栏保持(“停放”)在视图的底部

build议的解决scheme:

响应键盘显示通知,手动设置工具栏的animation

此解决scheme不符合第二个要求的特殊情况( 工具栏将在键盘出现并消失时跟随键盘 ):

  • 在iOS 7中,引入了UIScrollViewKeyboardDismissMode 。 它启用交互式手势来解除键盘。 随着用户翻过键盘的上边缘,键盘框架逐渐跟随。 这个解决scheme没有任何东西来适应这种行为,只是把工具栏留在它的animation位置。

另外,这个解决scheme也不能满足第三个要求的特殊情况( 当键盘可见时,工具栏应该保持在键盘顶部 ):

  • 回转。 这个解决scheme需要额外的,烦人的无关代码(我们将在下一个build议的解决scheme中看到)旋转工具栏以响应设备旋转。

解决scheme的另一个问题是:

  • 键盘高度。 有了这个解决scheme,工具栏并不被认为是键盘高度的一部分,所以必须编写额外的代码来支持内容的正确插入。

下一个build议的解

使用UIResponderinputAccessoryView

这个解决scheme似乎是苹果打算支持这种行为的方式,因为它解决了手动设置工具栏的所有缺点。 但是这个解决scheme完全不符合第四个要求( 当键盘被隐藏时,工具栏停留在视图的底部(“停靠”) )。


看来解决scheme是使用UIResponderinputAccessoryView ,但不知何故使inputAccessoryView不能移动到视图下方。 我正在寻找干净的代码来完成这一点。 在其他地方有精心的,几乎是高尚的尝试,但如前所述,他们不符合要求。

在我的具体情况下,我正在寻找使用UINavigationController的工具栏,这需要额外的问题,因为这不是UINavigationController行为。 无论如何,我愿意介绍一些哈克修补程序来实现这一点。

我刚刚被Jason Foreman(@threeve)展示给了他。 在你的视图控制器(是的,视图控制器)添加inputAccessoryView:并返回您想停靠在底部的视图,并随键盘移动。 它只是工作。 该视图实际上不需要在您的视图层次结构中,它将被视图控制器自动插入。

编辑:也执行canBecomeFirstResponder并返回YES(如Max Seelemann所述)。 reloadInputViews也可以得心应手。

Jonathan Badeen的上述解决scheme为我工作。 这是来自Arik的代码,展示了如何实现它(这应该放在适当的视图控制器中):

  - (BOOL)canBecomeFirstResponder{ return YES; } - (UIView *)inputAccessoryView{ return self.inputAccessoryToolbar; // where inputAccessoryToolbar is your keyboard accessory view } 

对于那些寻找Swift版本的人:

连接你的工具栏(在我的情况下' myToolBar ')到您的视图控制器。 然后重写canBecomeFirstResponder方法并覆盖getter的inputAccessoryViewvariables。 另外不要忘记添加self.myToolBar.removeFromSuperview()否则Xcode会抱怨。

 class ViewController: UIViewController { @IBOutlet var myToolBar: UIToolbar! override func canBecomeFirstResponder() -> Bool { return true } override var inputAccessoryView:UIView{ get{ return self.myToolBar } } override func viewDidLoad() { super.viewDidLoad() self.myToolBar.removeFromSuperview() } } 

Slack的优秀人员SlackTextViewController提供了一个优秀的,易于实现的开源解决scheme。

以下是如何通过四个步骤实现一个停靠工具栏的视图:

  1. 将该窗格安装到您的项目中。 ( http://cocoapods.org/?q=SlackTextViewController
  2. 如果你在Swift中编写一个应用程序,创build一个头来连接你的Swift代码和它们的Obj-C类。 这是一个很好的快速演练 。 (一旦类被翻译成Swift,桥接头将不是必需的,任何人都希望在这方面进行协作?)
  3. 创build一个从SLKTextViewControllerinheritance的MessageViewController ,不需要再编写比这更多的代码:

     import Foundation import UIKit class MessageViewController: SLKTextViewController { required init(coder aDecoder: NSCoder!) { super.init(coder: aDecoder) } } 
  4. 在Storyboard中,创build一个从MessageViewControllerinheritance的View Controller。
  5. 在设备或模拟器上testing应用程序,您会看到一个漂亮的停靠的文本栏,同时(作为奖励)随着用户写入额外的文本行而扩展。

在Slack的队伍中提取这样一个有用的吊舱。

所以我知道这是一个旧的post,我不知道你是否解决这个问题,但我find了一个方法来得到这个工作。 我相信inputAccessoryView中有一个bug,但是我创build了一个hacky解决scheme来performance消息应用程序的行为。 我想我提供了所有必要的代码来实现这个工作。 我将尝试在不久的将来创build一个更合适的博客文章,并对我的发现进行更深入的描述。 有任何问题,请告诉我。

 @property(nonatomic,assign)BOOL isFirstKeyboard; //workaround for keyboard bug @property(nonatomic,assign)BOOL isViewAppear; @property(nonatomic,strong)ChatBarView *chatView; //custom chat bar view @property(nonatomic,strong)UIView *footerPadView; //just to add some nice padding //////////////////////////////////////////////////////////////////////////////////////////////////// //in the view did load - (void)viewDidLoad { //more app specific code... self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive; self.chatView.textView.inputAccessoryView = self.chatView; } //////////////////////////////////////////////////////////////////////////////////////////////////// -(void)done { self.isFirstKeyboard = YES; [self.chatView.textView becomeFirstResponder]; } //////////////////////////////////////////////////////////////////////////////////////////////////// - (void) moveTextViewForKeyboard:(NSNotification*)aNotification up:(BOOL)up { if(!self.isViewAppear) return; //NSLog(@"keyboard is: %@", up ? @"UP" : @"Down"); if(!up && !self.isFirstKeyboard) [self performSelector:@selector(done) withObject:nil afterDelay:0.01]; else if(!up & self.isFirstKeyboard) { self.isFirstKeyboard = NO; [self.view addSubview:self.chatView]; CGRect frame = self.chatView.frame; frame.origin.y = self.view.frame.size.height - self.chatView.frame.size.height; self.chatView.frame = frame; } else { NSDictionary* userInfo = [aNotification userInfo]; NSTimeInterval animationDuration; UIViewAnimationCurve animationCurve; CGRect keyboardEndFrame; [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve]; [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration]; [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame]; // Animate up or down [UIView beginAnimations:nil context:nil]; if(up) [UIView setAnimationDuration:0.2]; else [UIView setAnimationDuration:0.3]; [UIView setAnimationCurve:animationCurve]; CGRect frame = self.footerPadView.frame; CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil]; if (up) frame.size.height = keyboardFrame.size.height - self.chatView.frame.size.height; else frame.size.height = 0; self.footerPadView.frame = frame; self.tableView.tableFooterView = self.footerPadView; [UIView commitAnimations]; } } //////////////////////////////////////////////////////////////////////////////////////////////////// - (void)keyboardWillShow:(NSNotification *)aNotification { [self moveTextViewForKeyboard:aNotification up:YES]; } //////////////////////////////////////////////////////////////////////////////////////////////////// - (void)keyboardWillHide:(NSNotification *)aNotification { [self moveTextViewForKeyboard:aNotification up:NO]; } ////////////////////////////////////////////////////////////////////////////////////////////////////