iPad分离键盘

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

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

首先,用户可以使用三种方式卸下键盘:

  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}}";
}

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

9
额外 编辑
意见: 1

2 答案

没有明确的方法没有。

我在下一步中解决了这个问题:

  1. 获取目前的方向。
  2. 如果orientation为Landscape,那么我得到UIKeyboardFrameEndUserInfoKey的 height 。它必须等于216.这意味着键盘是分离模式,否则不是;
  3. 如果orientation为Portrait,那么我得到UIKeyboardFrameEndUserInfoKey的 height 。它必须等于216.这意味着键盘是分离模式,否则不是;

例如,我更新了我的要点。使用convertRect方法。

3
额外
当心,这不是一个好的解决方案。键盘高度根据语言环境,ios版本和设备而变化。
额外 作者 capikaw,
没有不同。 216不是像素,其点参数与分辨率无关。但是这不适用于iPhone 4和5.而iPhone没有分离键盘。他们改变形式因素。
额外 作者 Bimawa,
@capikaw 216不是静态参数,它带有 UIKeyboardFrameEndUserInfoKey 键。
额外 作者 Bimawa,
自推出iPad Mini以来,这会变得更加困难。我甚至还没有碰过iOS 7
额外 作者 Takeshi Kaga,

这是确定键盘是否分裂的一种有点冒失,但可靠的方法。

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 (你可以使用一个空视图)。

Note: The behavior of textField.inputAccessoryView.superview is quite finicky, and usually depends on the keyboard having been displayed once before calling superview. Also to pass the App Store submission process I removed the 'UI' prefix from the private class names. That's not a guarantee Apple will not flag your app, but this approach has been used successfully before.

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

1
额外
这可能会工作,但为什么你访问子视图0 0 1 0?
额外 作者 Daij-Djan,
这至少应该使用类名来完成,所以它不会崩溃
额外 作者 Daij-Djan,
没有。你可以...名字不是真的被认为是极限 - 符号是。我做了N个应用程序,并且已经做了多年
额外 作者 Daij-Djan,
所以类似if(view.className rangeOfString:@“Splitview”或className hasPrefix:@“UIButtton”...
额外 作者 Daij-Djan,
我更喜欢这个比较点大小,我认为...
额外 作者 Daij-Djan,
因为它逐步通过视图层次结构查找实际呈现键盘的私有类。我用显示查看键盘视图的状态。请参阅此处
额外 作者 cagey,
在生产中使用这个确切的代码显然是一个坏主意,但希望答案对某些人仍然有用。
额外 作者 cagey,
你不能使用classnames,因为它们是私人的,所以在App Store上是不允许的。显然,如果你在生产代码中实现它,它应该比我的简短答案更安全。 UIKit每次生成键盘的方式都是一致的,所以这种方法可以可靠地工作。
额外 作者 cagey,
哦!在这种情况下,我想你可以更可靠地穿过每个孩子,以确保你拉动你需要的确切视图。考虑到这一点,我会更新答案。
额外 作者 cagey,