Animate UIView沿键盘出现动画

Sas*_*ter 15 animation uikeyboard ios

我正在使用UIKeyboardWillShowNotificationUIKeyboardWillHideNotification动画沿键盘显示动画使用UIKeyboardAnimationDurationUserInfoKey,UIKeyboardAnimationCurveUserInfoKeyUIKeyboardFrameEndUserInfoKey.

一切正常,只要元素开始位置在屏幕的底部.我的元素(在截图输入框)开始的UITabBarController以上,所以如果我的动画开始有键盘的UITextField,沿着动画缩小,直到它到达其终点之间的差距.

什么我真的寻找是这样的:"制作具有相同的动画曲线,但开始移动,如果键盘达到我的美星的位置".

如果我想补充的延迟启动动画它不会与宽松正确的,这可能会在未来的iOS版本打破.

如果你与我分享你的想法会很棒.:-)

键盘关闭 键盘打开 键盘动画(见差距

Tom*_*ift 14

通常有两种方法可以将视图保持在键盘上方,因为它可以动画到位.如您所知,第一个是监听UIKeyboardWillShowNotification并使用userData中的伴随持续时间/曲线/帧值来帮助您在键盘上方定位和设置视图动画.

第二种方法是为调用键盘inputAccessoryView的视图(UITextField这里)提供一个. (我意识到这不会提供你所要求的效果,一旦键盘进入它就会"推"工具栏/文本字段.但稍后更多.) iOS会将你的inputAccessoryView作为视图也是键盘的父母,并将它们组合起来.根据我的经验,这提供了最好看的动画.我不认为我使用这种方法有过完美的动画UIKeyboardWillShowNotification,特别是现在在iOS7中,键盘动画结束时有一点反弹.UIKit Dynamics可能还有一种方法可以将这种反弹应用到您的视图中,但是使其与键盘完美同步会很困难.

以下是我过去为类似于您的场景所做的事情:底部UIToolbar有一个UITextField用于输入的customView栏按钮项目.在你的情况下,它位于a UITabBar.该ITextField有一个自定义inputAccessoryView设置,这是另一种 UIToolbar另一个 UITextField.

当用户点击文本字段并成为第一响应者时,键盘会随着第二个工具栏/文本字段一起动画到位(这个转换看起来非常好!).当我们注意到这种情况发生时,我们将firstResponder从第一个文本字段转换到第二个文本字段,以便在键盘就位后它具有闪烁的插入符号.

诀窍是当您确定结束编辑的时间时该怎么做.首先,你必须在第二个文本字段上使用resignFirstResponder,但如果你不小心,那么系统会将第一个响应者状态传回原始文本字段!所以你必须防止这种情况,因为否则你将处于向前传递第一个响应者的无限循环中,键盘将永远不会消失.其次,您需要将输入到第二个文本字段的任何文本镜像回到第一个文本字段.

这是这种方法的代码:

@implementation TSViewController
{
    IBOutlet UIToolbar*     _toolbar; // parented in your view somewhere

    IBOutlet UITextField*   _textField; // the customView of a UIBarButtonItem in the toolbar

    IBOutlet UIToolbar*     _inputAccessoryToolbar; // not parented.  just owned by the view controller.

    IBOutlet UITextField*   _inputAccessoryTextField; // the customView of a UIBarButtonItem in the inputAccessoryToolbar
}

- (void) viewDidLoad
{
    [super viewDidLoad];

    _textField.delegate = self;
    _inputAccessoryTextField.delegate = self;

    _textField.inputAccessoryView = _inputAccessoryToolbar;
}

- (void) textFieldDidBeginEditing: (UITextField *) textField
{
    if ( textField == _textField )
    {
        // can't change responder directly during textFieldDidBeginEditing.  postpone:
        dispatch_async(dispatch_get_main_queue(), ^{

            _inputAccessoryTextField.text = textField.text;

            [_inputAccessoryTextField becomeFirstResponder];
        });
    }
}

- (BOOL) textFieldShouldBeginEditing: (UITextField *) textField
{
    if ( textField == _textField )
    {
        // only become first responder if the inputAccessoryTextField isn't the first responder.
        return ![_inputAccessoryTextField isFirstResponder];
    }
    return YES;
}

- (void) textFieldDidEndEditing: (UITextField *) textField
{
    if ( textField == _inputAccessoryTextField )
    {
        _textField.text = textField.text;
    }
}

// invoke this when you want to dismiss the keyboard!
- (IBAction) done: (id) sender
{
    [_inputAccessoryTextField resignFirstResponder];
}

@end
Run Code Online (Sandbox Code Playgroud)

我能想到最后一种可能性.上述方法具有两个独立工具栏/文本字段的缺点.你理想的只是其中的一组,你希望它看起来键盘"推"它们(或拉下它们).实际上动画足够快,我认为大多数人都不会注意到上面的方法有两套,但也许你不喜欢这样.

最后一种方法是监听键盘显示/隐藏,并使用a CADisplayLink同步动画工具栏/文本字段,因为它实时检测键盘位置的变化.在我的测试中它看起来很不错.我看到的主要缺点是工具栏的位置稍微滞后.我正在使用自动布局,转换到传统的帧定位可能会更快.另一个缺点是键盘视图层次结构的依赖性没有显着变化.这可能是最大的风险.

还有另外一个技巧.工具栏使用约束定位在我的故事板中.距离视图底部的距离有两个约束条件.一个绑定到IBOutlet"_toolbarBottomDistanceConstraint",这是代码用于移动工具栏的内容.该约束是具有"等于"关系的"垂直空间"约束.我将优先级设置为500.存在第二个并行的"垂直空间"约束,其具有"大于或等于"关系.此常量是到视图底部的最小距离(例如,在标签栏上方),优先级为1000.有了这两个约束,我可以设置工具栏从底部到任意值的距离我喜欢,但它永远不会低于我的最低价值.

最后,也许您可​​以将此方法与您已经获得的方法混合使用:使用CADisplayLink回调来检测键盘何时"遇到"您的工具栏,然后不是手动定位工具栏以用于动画的其余部分,使用真实的UIView动画将工具栏动画到位.您可以将持续时间设置为键盘显示动画持续时间减去已经发生的时间.

@implementation TSViewController
{
    IBOutlet UITextField*           _textField;

    IBOutlet UIToolbar*             _toolbar;

    IBOutlet NSLayoutConstraint*    _toolbarBottomDistanceConstraint;

    CADisplayLink*                  _displayLink;
}

- (void) dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver: self];
}

- (void) viewDidLoad
{
    [super viewDidLoad];

    [self.view addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector( dismiss:) ]];

    _textField.inputAccessoryView = [[UIView alloc] init];

    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(keyboardWillShowHide:)
                                                 name: UIKeyboardWillShowNotification
                                               object: nil];

    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(keyboardWillShowHide:)
                                                 name: UIKeyboardWillHideNotification
                                               object: nil];

    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(keyboardDidShowHide:)
                                                 name: UIKeyboardDidShowNotification
                                               object: nil];

    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(keyboardDidShowHide:)
                                                 name: UIKeyboardDidHideNotification
                                               object: nil];
}

- (void) keyboardWillShowHide: (NSNotification*) n
{
    _displayLink = [CADisplayLink displayLinkWithTarget: self selector:  @selector( tick: )];
    [_displayLink addToRunLoop: [NSRunLoop currentRunLoop] forMode: NSRunLoopCommonModes];
}

- (void) keyboardDidShowHide: (NSNotification*) n
{
    [_displayLink removeFromRunLoop: [NSRunLoop currentRunLoop] forMode: NSRunLoopCommonModes];
}

- (void) tick: (CADisplayLink*) dl
{
    CGRect r = [_textField.inputAccessoryView.superview.layer.presentationLayer frame];
    r = [self.view convertRect: r fromView: _textField.inputAccessoryView.superview.superview];

    CGFloat fromBottom = self.view.bounds.size.height - r.origin.y;
    _toolbarBottomDistanceConstraint.constant = fromBottom;
}

- (IBAction) dismiss: (id) sender
{
    [self.view endEditing: YES];
}

@end
Run Code Online (Sandbox Code Playgroud)

这是视图层次结构和约束:

在此输入图像描述