【问题标题】:iPad split-keyboardiPad 分体式键盘
【发布时间】:2012-05-31 17:38:14
【问题描述】:

我正在创建一个类似于 iPad 的 iMessage 应用程序的应用程序,它可以发送消息。因此,当显示键盘时,消息视图和输入附件视图的底部有一个输入视图。此外,当键盘在停靠或取消停靠时显示时,消息视图必须正确调整大小。

我遇到的问题是UIKeyboardWillChangeFrameNotification进来的通知数据不一致。

首先,用户可以通过 3 种方式取消键盘:

  1. 按住右下键,然后向上滑动
  2. 长按右下键,在弹出菜单时选择“取消停靠”
  3. 长按右下键,弹出菜单时选择“拆分”

对于案例#1,来自 UIKeyboardWillChangeFrameNotification 的通知数据是一致的。这是数据:

userInfo = {
    UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 0}, {768, 304}}";
}

对于案例 #2 和 #3,数据不一致,这是我收到的:

userInfo = {
    UIKeyboardAnimationCurveUserInfoKey = 0;
    UIKeyboardAnimationDurationUserInfoKey = "0.25";
    UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {768, 304}}";
    UIKeyboardCenterBeginUserInfoKey = "NSPoint: {384, 872}";
    UIKeyboardCenterEndUserInfoKey = "NSPoint: {384, 1136}";
    UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 0}, {768, 304}}";
    UIKeyboardFrameChangedByUserInteraction = 0;
    UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, -264}, {768, 304}}";
}

这里奇怪的是,当我在案例 #2 或 #3 下侦听 UIKeyboardDidChangeFrameNotification 时,数据按预期进入:

userInfo = {
    UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 0}, {768, 304}}";
}

为什么通知数据不同?有没有人找到一种明确的方法来检测拆分键盘事件?

【问题讨论】:

    标签: objective-c ipad keyboard-events


    【解决方案1】:

    没有明确的方法没有。

    我会在接下来的步骤中解决这个问题:

    1. 获取当前方向。
    2. 如果方向是横向,那么我会得到 UIKeyboardFrameEndUserInfoKey 的 高度。必须等于216。表示键盘为Split mode,否则不是;
    3. 如果方向是纵向,那么我得到 UIKeyboardFrameEndUserInfoKey 的 高度。必须等于216。表示键盘为Split mode,否则不是;

    我用 convertRect 方法更新了我的gist for example.

    【讨论】:

    • 自从 iPad Mini 推出以来,这将变得更加困难。我什至还没接触过 iOS 7...
    • 没有区别。 216 不是像素,它的点参数与分辨率无关。但这不适用于 iPhone 4s 和 5。而且 iPhone 没有拆分键盘。它们改变了外形。
    • 当心,这不是一个好的解决方案。键盘高度因区域设置、ios 版本和设备而异。
    • @capikaw 216 不是静态参数,它是一个带有UIKeyboardFrameEndUserInfoKey 键的数字。
    【解决方案2】:

    这是一种确定键盘是否拆分的可靠方法。

    NSArray *classPath = @[
      @"KeyboardAutomatic",
      @"KeyboardImpl",
      @"KeyboardLayoutStar",
      @"KBKeyplaneView",
      @"KBSplitImageView"
    ];
    UIView *splitView = textField.inputAccessoryView.superview;
    for (NSString *className in classPath) {
      for (UIView *subview in splitView.subviews) {
        if ([NSStringFromClass([subview class]) rangeOfString:className].location != NSNotFound) {
          splitView = subview;
          break;
        }
      }
    }
    BOOL isSplit = [splitView.subviews count] > 1;
    

    显然,为了让它工作,你需要一个 UITextField/UITextView 和一个非零 inputAccessoryView(你可以只使用一个空视图)。

    注意:textField.inputAccessoryView.superview 的行为相当挑剔,通常取决于在调用superview 之前已经显示过一次键盘。此外,为了通过 App Store 提交过程,我从私有类名中删除了“UI”前缀。这并不能保证 Apple 不会标记您的应用,但这种方法之前已经成功使用过。

    我只在 iOS7 上测试过,但如果它在其他版本的 iOS 上不起作用,可以使用类似的方法。

    【讨论】:

    • 这可能行得通,但你为什么要访问子视图 0 0 1 0?
    • 因为它逐步遍历视图层次结构,寻找实际呈现键盘的私有类。我使用Reveal 来查看键盘视图的查找状态。见here
    • 在生产中使用这个确切的代码显然是个坏主意,但希望答案对某些人仍然有用。
    • 至少应该使用类名来完成,这样它才不会崩溃
    • 你不能使用类名,因为它们是私有的,所以在 App Store 上是不允许的。显然,如果您在生产代码中实现这一点,它应该比我的简短回答更安全。 UIKit每次生成键盘的方式都是一致的,所以这个方法确实工作可靠。
    猜你喜欢
    • 2013-06-06
    • 1970-01-01
    • 1970-01-01
    • 2011-02-07
    • 2011-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多