在 iOS7 中边缘滑动时,使键盘与 UIView 同步动画

Posted

技术标签:

【中文标题】在 iOS7 中边缘滑动时,使键盘与 UIView 同步动画【英文标题】:Animate the keyboard in sync with the UIView while edge-swiping back in iOS7 【发布时间】:2014-01-07 23:34:51 【问题描述】:

我希望在 ios7 中获得类似于 Messages 应用程序(在大多数短信应用程序中也很常见)的行为,其中在对话视图中从屏幕左边缘向右滑动的行为类似于 UINavigationController 中的后退按钮。

我已经设法实现了这种行为,但是,如果键盘在呈现视图中打开,当我开始向后滑动时,键盘会卡住并且在我移动手指时不会随着视图向右移动。我想将键盘和呈现视图作为一个单元进行动画处理,而不是好像键盘位于其他视图之上并且它们在其后面进行动画处理,这就是我现在得到的(参见第二个屏幕截图):

(更新:请注意,键盘最终会在主视图动画完成后消失;我关注的是键盘滑动过程中的位置, 并且当您在中途继续触摸设备时,这与实际视图不同步。第二个屏幕截图阐明了这种期望的行为。我也想知道为什么它不是默认设置。)

通过简单地在 Xcode 5.0.2 中创建一个新的主从 iPhone 应用程序并在 StoryBoard 中的详细视图(最好在上半部分的某个位置)添加一个文本字段,运行该应用程序,很容易复制该问题,添加一个项目,点击它进入详细视图,然后单击您添加的文本字段。从设备左侧边缘滑动,同时将手指放在设备上,您会发现问题。

期望的行为:

当前行为:

【问题讨论】:

请发布您用于设置边缘滑动手势行为的代码。 UINavigationController 应该为您处理键盘,但是如果您正在做一些自定义的事情,那么您可能会遇到这种行为。 @NoahWitherspoon 感谢您的评论。我再次尝试通过从头开始创建一个新项目而不编写任何代码来隔离问题:您可以通过简单地创建一个新的 Master-Detail iPhone 应用程序并将一个文本字段拖放到详细视图上来复制此问题。运行应用程序,在主视图中添加一个项目,单击它以转到详细视图。点击文本字段并尝试边缘滑动手势。它会让键盘保持在顶部。 你的问题解决了吗?! 【参考方案1】:

不幸的是,没有内置的方法可以做到这一点。我真的希望UIViewControllers 会有类似UIScrollViewKeyboardDismissModeInteractive 的东西。

现在,要在 viewController 之间做任何动画,你应该使用 transitionCoordinator:

- (BOOL)animateAlongsideTransition:(void (^)(id <UIViewControllerTransitionCoordinatorContext>context))animation
                        completion:(void (^)(id <UIViewControllerTransitionCoordinatorContext>context))completion;

- (BOOL)animateAlongsideTransitionInView:(UIView *)view
                               animation:(void (^)(id <UIViewControllerTransitionCoordinatorContext>context))animation
                              completion:(void (^)(id <UIViewControllerTransitionCoordinatorContext>context))completion;

对于键盘,你应该这样做:

[self.transitionCoordinator animateAlongsideTransitionInView:self.keyboardSuperview
                                                   animation:
^(id<UIViewControllerTransitionCoordinatorContext> context) 
    self.keyboardSuperview.x = self.view.width;

                                                  completion:nil];

至于keyboardSuperview - 你可以通过创建一个假的inputAccessoryView 来获得:

self.textField.inputAccessoryView = [[UIView alloc] init];

那么superview就是self.textField.inputAccessoryView.superview

【讨论】:

感谢您的回答。我曾考虑过这方面的事情,并在您提出后尝试使其再次起作用。问题是,在 iOS 7 中,我似乎无法访问虚拟 inputAccessoryView 的超级视图以访问键盘。它似乎总是nil 键盘隐藏时可能为nil。如果不想弄乱键盘通知,可以在viewDidLoad方法中添加inputAccessoryView,并将检索它的所有逻辑和添加动画放在viewWillDisappear:方法中。 我终于设法通过在init 中添加虚拟附件视图来做到这一点,并在keyboardDidShow 事件中捕获了虚拟键盘(键盘视图)的超级视图。在viewWillDisappear 中,我发起了过渡。似乎这就是神奇的组合,任何偏离它的地方都失败了。谢谢! animateAlongsideTransition:completion: 方法应该去哪里?我对新的 UIViewController 交互式过渡和 transitionCoordinator 不是很熟悉,所以你能提供的任何帮助都会很棒。 @Matt viewWillDisappear:。我还将此代码添加到beginAppearanceTransition:animated:,它对我有用。【参考方案2】:

它应该只是自动工作,但有时由于某些条件它不会。

如果当前firstResponder 位于活动UIViewController 内部并且在整个UINavigationController 机制中消失,则将自动执行预期的键盘动画(水平)。因此,有时这种默认行为会被其他奇怪的因素破坏,键盘开始以向下滑动动画而不是水平动画消失。

我花了几天时间调试内部 UIKit 的东西(围绕方法 needDeferredTransitionallowCustomTransition 和其他方法)来找到一个在我的案例中起关键作用的特殊因素。

我发现UIPeripheralHost 内部的逻辑检查frame 的当前UIViewConroller 的视图,frameUINavigationController 的视图(容器)和屏幕size,如果一切都没有t 相等,UIPeripheralHost 决定当前情况看起来像模态窗口并设置标志allowCustomTransition = NO。关闭UINavigationController 特定的水平动画。

解决frames 的问题完全解决了我的问题。

如果您遇到同样的问题,您可以尝试围绕这些私有方法调试内部 UIKit 的东西,并找到关闭水平动画的条件:

https://github.com/JaviSoto/iOS8-Runtime-Headers/blob/master/Frameworks/UIKit.framework/UIPeripheralHost.h

https://github.com/JaviSoto/iOS8-Runtime-Headers/blob/master/Frameworks/UIKit.framework/_UIViewControllerKeyboardAnimationStyle.h

【讨论】:

【参考方案3】:

如果你不需要任何特别的东西,你可以使用https://github.com/cotap/TAPKeyboardPop。

在我的例子中,我有一些与 UIKeyboardWillShowNotificationUIKeyboardWillHideNotification 相关的逻辑,这些逻辑是在“滑动到返回”手势时触发的。我结合了this answer 和TAPKeyboardPop,这就是我所拥有的:

- (void)beginAppearanceTransition:(BOOL)isAppearing animated:(BOOL)animated 
    [super beginAppearanceTransition:isAppearing animated:animated];
    if (isAppearing || !animated || !_keyboardIsShown) 
        return;
    
    if ([self respondsToSelector:@selector(transitionCoordinator)]) 
        UIView *keyboardView = self.searchBar.inputAccessoryView.superview;
        [self.searchBar becomeFirstResponder];
        [self.transitionCoordinator animateAlongsideTransitionInView:keyboardView
                                                           animation:^(id<UIViewControllerTransitionCoordinatorContext> context)
         
             CGRect endFrame = CGRectOffset(keyboardView.frame, CGRectGetWidth(keyboardView.frame), 0);
             keyboardView.frame = endFrame;
          completion:^(id<UIViewControllerTransitionCoordinatorContext> context)
         
             if (![context isCancelled]) 
                 [self.searchBar resignFirstResponder];
             
         ];
    

编辑:

我添加了 >iOS7 支持和知道何时显示键盘的逻辑(_keyboardIsShown 设置在 UIKeyboardWillShowNotification/UIKeyboardWillHideNotificationUIKeyboardDidHideNotification/UIKeyboardDidShowNotification 中)。

【讨论】:

嘿。你能更详细地解释一下这段代码的用途吗? @StianHøiland 现在我手上没有代码(这个答案中的代码很奇怪,不知道为什么self.searchBar 在那里,可能应该是文本),但据我记得 -它使键盘随着视图控制器移动,正在滑动(有问题的第一个屏幕截图)。

以上是关于在 iOS7 中边缘滑动时,使键盘与 UIView 同步动画的主要内容,如果未能解决你的问题,请参考以下文章

是否可以在 iOS 模拟器中进行边缘滑动?

如何在 UIView 中设置滚动视图以向上滑动被键盘隐藏的文本字段?

iOS 7 上的 UIPopoverController 和键盘导致奇怪的动画

使用滑动手势关闭键盘

模糊包含键盘及其下方内容的 UIView (iOS 7)

iOS7 键盘返回/完成/搜索色调颜色