53

我正在尝试实现与 Apple 消息应用程序中的底部文本输入栏类似的定位行为。

我尝试了很多方法,搜索了高低,并且有很多类似的问题,但没有一个令人满意。

要指定:

  1. UIToolbar视图底部有一个
  2. 工具栏是随着键盘的出现和消失而跟随键盘
  3. 当键盘可见时,工具栏应位于键盘顶部
  4. 当键盘被隐藏时,工具栏保持(“停靠”)在视图的底部

建议的解决方案:

手动为工具栏设置动画以响应键盘外观通知

此方案不满足第二个要求的特殊情况(工具栏是随着键盘的出现和消失而跟随键盘):

  • 在 iOS 7 中,UIScrollViewKeyboardDismissMode被引入。它启用了关闭键盘的交互式手势。随着用户平移经过键盘的顶部边缘,键盘框架逐渐跟随。该解决方案对适应这种行为没有任何作用,只是将工具栏搁置在其动画位置。

此外,此解决方案也无法满足第三个要求的特殊情况(当键盘可见时工具栏应保持在键盘顶部):

  • 回转。该解决方案需要额外的、令人讨厌的无关代码(正如我们将在下一个建议的解决方案中看到的那样)来旋转工具栏以响应设备旋转。

此解决方案的另一个问题:

  • 键盘高度。使用此解决方案,工具栏不假定为键盘高度的一部分,因此必须编写附加代码以支持正确插入内容。

下一个建议的解决方案:

使用UIResponderinputAccessoryView

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


似乎解决方案是使用UIResponder's inputAccessoryView,但以某种方式使inputAccessoryViewnot 在视图下方移动。我正在寻找干净的代码来实现这一点。其他地方也有精心设计,几乎是高尚的尝试,但如前所述,它们不符合要求。

在我的特殊情况下,我希望使用UINavigationController' 工具栏,这会带来其他问题,因为这不是UINavigationController. 无论如何,我愿意介绍一些 hacky 修复来实现这一点。

4

5 回答 5

60

Jason Foreman(@threeve)刚刚向我展示了“解决方案”。在您的视图控制器(是的,视图控制器)上添加inputAccessoryView:并返回您想要停靠在底部并使用键盘移动的视图。它只是工作。视图实际上不需要在您的视图层次结构中,它将由视图控制器自动插入。

编辑:还实现 canBecomeFirstResponder 并返回 YES(如 Max Seelemann 所述)。reloadInputViews 也很方便。

于 2014-05-27T03:23:28.483 回答
32

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

    - (BOOL)canBecomeFirstResponder{

        return YES;

    }

    - (UIView *)inputAccessoryView{

        return self.inputAccessoryToolbar;  
     // where inputAccessoryToolbar is your keyboard accessory view

    }
于 2014-08-08T22:37:53.050 回答
14

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

将您的工具栏(在我的情况下为“ myToolBar”)连接到您的视图控制器。然后覆盖canBecomeFirstResponder方法并覆盖getterinputAccessoryView变量。也不要忘记添加,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()
    }
}
于 2015-06-25T17:24:26.190 回答
6

Slack 的好人为此提供了一个出色的、易于实现的开源解决方案:SlackTextViewController

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

  1. 将 pod 安装到您的项目中。( http://cocoapods.org/?q=SlackTextViewController )
  2. 如果您正在使用 Swift 编写应用程序,请创建一个标头以在您的 Swift 代码和它们的 Obj-C 类之间架起桥梁。这是一个很好的快速演练。(一旦类被翻译成 Swift 就不需要桥接头了,有人愿意合作吗?)
  3. 创建一个MessageViewController继承自 的SLKTextViewController,无需编写更多代码:

    import Foundation
    import UIKit
    
    class MessageViewController: SLKTextViewController {
    
        required init(coder aDecoder: NSCoder!) {
            super.init(coder: aDecoder)
        }
    }
    
  4. 在 Storyboard 中,创建一个继承自 MessageViewController 的 View Controller。
  5. 在设备或模拟器上测试应用程序,您会看到一个漂亮的停靠文本栏(作为奖励),当用户编写额外的文本行时,它也会扩展。

对 Slack 团队提取如此有用的 pod 的支持。

于 2014-10-20T14:00:41.883 回答
2

所以我知道这是一篇旧帖子,我不确定你是否解决了这个问题,但我找到了一种让它工作的方法。我相信 inputAccessoryView 中存在错误,但我创建了一个 hacky 解决方案来表现消息应用程序的行为方式。我想我提供了所有必要的代码来解决这个问题。我将尝试在不久的将来创建一篇更合适的博客文章,对我的发现进行更深入的描述。有任何问题,请告诉我。

@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];
}
////////////////////////////////////////////////////////////////////////////////////////////////////
于 2013-12-24T05:11:28.573 回答