iOS:在 iPad 模式视图中获取键盘点的顶部?

Posted

技术标签:

【中文标题】iOS:在 iPad 模式视图中获取键盘点的顶部?【英文标题】:iOS: Get top of keyboard point in iPad modal view? 【发布时间】:2015-05-20 22:35:50 【问题描述】:

我需要在显示键盘时调整“消息栏”,并且在使用 iPad 模态视图控制器时遇到问题。 “消息栏”在显示时应位于键盘的正上方,然后在键盘隐藏时位于模式的底部(类似于消息应用程序样式)。

问题是我需要根据模态坐标系获得键盘框架的最高点。 我发现这个答案在理论上似乎是正确的,但不起作用(How can I find portion of my view which isn't covered by the keyboard (UIModalPresenationStyleFormSheet)?):

仅供参考当显示键盘时,主窗口中的键盘框架(即“keyboardFrame”)= (-84.0, 526.0, 768.0, 264.0)。为模态视图控制器坐标系翻译时的键盘框架(即'newSize')= (-168.0, 292.0, 768.0, 264.0)*

// Convert the keyboard rect into the view controller's coordinate system
// The fromView: nil means keyboardRect is in the main window's coordinate system
let newSize = self.view.convertRect(keyboardFrame, fromView: nil)

// And then this is the part that gets covered!
let keyboardCoveredHeight = self.view.bounds.height - newSize.origin.y
self.messageToolbar.bottomConstraint.constant = -keyboardCoveredHeight

【问题讨论】:

This is what you need to read @Lefteris - 我确实使用它作为指导。如 OP 中所述,问题出在 iPad 中使用模态视图控制器时。键盘框架相对于主窗口,而不是模式。因此,为了将底部约束设置为正确的值,我需要知道键盘顶部的位置(就模态坐标系而言)。但目前这样做的方法并没有给出准确的翻译值。 该文档说“我们在回调中获得的键盘框架始终以纵向表示”,这在 ios 8 中不再适用。在 iOS 8 中,旋转只是随着大小的变化而处理,因此不需要考虑设备的方向。 @AaronBrager 没错,但同样,这不是手头的问题。同样,问题是获得关于键盘顶部所在的模态视图控制器坐标系的“正确坐标”(显示在主窗口的坐标系中) 为什么不把你的 messageToolbar 作为 inputAccessoryView 呢?它将与键盘顶部对齐。 【参考方案1】:

我最终使用熟悉的类别在 iPad 模态视图中获得正确的键盘框架:

- (CGFloat)heightCoveredByKeyboardOfSize:(CGSize)keyboardSize

UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
CGRect frameInWindow = [self convertRect:self.bounds toView:nil];
CGRect windowBounds = self.window.bounds;

CGFloat keyboardTop;
CGFloat heightCoveredByKeyboard;

//Determine height of the view covered by the keyboard relative to current rotation

switch (orientation)

    case UIInterfaceOrientationLandscapeLeft:
    case UIInterfaceOrientationLandscapeRight:
        keyboardTop = windowBounds.size.height - keyboardSize.height;
        heightCoveredByKeyboard = windowBounds.size.height - frameInWindow.origin.y - keyboardTop;
        break;
    case UIInterfaceOrientationPortraitUpsideDown:
    default:
        keyboardTop = windowBounds.size.height - keyboardSize.height;
        heightCoveredByKeyboard = CGRectGetMaxY(frameInWindow) - keyboardTop;
        break;


return MAX(0.0f,heightCoveredByKeyboard);

连同 DAKeyboardControl(用于平移):

    // Use [unowned self] in closure for weak reference
    self.view.addKeyboardPanningWithFrameBasedActionHandler(nil, constraintBasedActionHandler:  [unowned self] (keyboardFrameInView, opening, closing) -> Void in
        if opening
        
            if UIDevice.isIpad()
            
                // iPad requires a different method due to use of modal view
                self.messageToolbar.bottomConstraint.constant = -self.view.heightCoveredByKeyboardOfSize(keyboardFrameInView.size)
            
            else
            
                self.messageToolbar.bottomConstraint.constant = -keyboardFrameInView.size.height
            
        

        if closing
        
            self.messageToolbar.bottomConstraint.constant = 0
        

        self.view.updateConstraintsIfNeeded()
        self.view.layoutIfNeeded()
    )

【讨论】:

【参考方案2】:

可以在keyboardDidShowNotification上以这种方式计算精确的重叠

let parentRelativeFrame = view.convert(view.frame, to: nil)
let viewBottomVerticalOffset = parentRelativeFrame.origin.y + parentRelativeFrame.height
let overlap = viewBottomVerticalOffset - keyboardFrame.origin.y

【讨论】:

【参考方案3】:

我认为您遇到了两个问题之一(可能两者都有):

    在 iOS 8 中,您必须从屏幕坐标空间转换键盘的矩形 在 iPad 上,当显示键盘时,工作表视图有时会向上移动一点,这种情况发生在键盘显示之后,因此您需要再次计算结果viewWillLayoutSubviews

这里是a sample project that does what you want。

为了后代,这里是有趣的源代码:

class TypingViewController: UIViewController 

    var keyboardHoverView: UIView! // your keyboard toolbar or whatever
    var lastKeyboardFrame : CGRect! // whenever you get a frame update, store it here

    override func viewDidLoad() 
        super.viewDidLoad()

        createKeyboardHoverView()
        observeKeyboard()
    

    func createKeyboardHoverView() 
        // make your keyboard toolbar
        keyboardHoverView = view
    

    func observeKeyboard() 
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)
    

    func keyboardWillShow(notification : NSNotification) 
        let dict = notification.userInfo!
        let frameValue = dict[UIKeyboardFrameEndUserInfoKey] as! NSValue
        lastKeyboardFrame = frameValue.CGRectValue()

        moveKeyboardView()
    

    func keyboardWillHide(notification : NSNotification) 
        moveKeyboardView()
    

    override func viewWillLayoutSubviews() 
        // this moves the view again, in case the modal view has shifted up
        moveKeyboardView()
    

    func moveKeyboardView() 
        if lastKeyboardFrame != nil 
            // this conversion is used in iOS 8 and differs from most online tutorials
            let frameInThisView = self.view.convertRect(lastKeyboardFrame, fromCoordinateSpace: view.window!.screen.coordinateSpace)

            var newRect = keyboardHoverView.frame
            newRect.origin.y = frameInThisView.origin.y - CGRectGetHeight(newRect)
            keyboardHoverView.frame = newRect

            println("Setting rect: \(newRect)")
        
    

【讨论】:

(请注意,我没有完全实现keyboardWillHide(),但您应该能够从中获得要点。) 感谢@Aaron 的详细信息!当我尝试使用更新的“fromCoordinate”版本进行转换时,键盘的帧大小仍然相同:(-168.0、292.0、768.0、264.0)。 '292' Y 原点就在咫尺之遥。模态视图为 600,键盘从底部开始覆盖大约 60 个点(使用消息栏的 44pt 高度作为指导)。不知道我在这里做错了什么。沮丧。 @JamesHickman 你能上传一个重现该行为的示例项目吗?另外,您是否使用相同的通知? (UIKeyboardWillShowNotification)?最后,如果您在应用程序中使用我的示例项目中的视图控制器会发生什么?

以上是关于iOS:在 iPad 模式视图中获取键盘点的顶部?的主要内容,如果未能解决你的问题,请参考以下文章

在 iOS 4.3 for iPad 中显示模式视图控制器是不是已更改?

拖动底部子视图之一时平滑更新顶部子视图(iOS)

ios7 iPad横向模式下的错误视图大小

在 iPad 横向模式 UISplitViewController iOS 上隐藏主视图

在 iPad 中呈现模式视图翻转视图

在iPad横向模式下隐藏主视图UISplitViewController iOS