如何计算 iPad 上模态视图的底部偏移量?

Posted

技术标签:

【中文标题】如何计算 iPad 上模态视图的底部偏移量?【英文标题】:How to calculate the bottom offset of a modal view on iPad? 【发布时间】:2013-09-13 00:17:50 【问题描述】:

当用户点击 UITextField 时,键盘会出现。我向上滚动 UITextField 以坐在键盘上方。这在 iPhone 上运行良好:

- (void) someWhere

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


- (void) onKeyboardShow:(NSNotification *)notification

    CGRect keyboardRect = [[[notification userInfo] 
        objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue
    ];

    if (keyboardRect.size.height >= IPAD_KEYBOARD_PORTRAIT_HEIGHT) 
        self.containerView.y = self.containerView.y - keyboardRect.size.width;
     else 
        self.containerView.y = self.containerView.y - keyboardRect.size.height;        
    

但是,它在 iPad 上坏了。在 iPad 上,模态视图控制器可以显示为仅占屏幕一部分的工作表。可以看到最后一个 UITextField 和 iPad 上的键盘之间有一个空隙。

UINavigationController* nav = [[UINavigationController alloc]
    initWithRootViewController:someRootViewController];
nav.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentViewController:nav animated:YES completion:nil];

我需要检测模态视图从屏幕底部的偏移并将其添加到 UITextField 的 Y 坐标。这将使 UITextField 与键盘顶部齐平。通过一些逆向工程,我通过遍历未记录的视图层次结构得到了模态视图的框架:

- (void) viewDidAppear:(BOOL)animated

    [super viewDidAppear:animated];
    // describe is a category function on UIView that prints out the frame
    [self.viewController.view.superview.superview.superview.superview describe];

x:114.000000, y: 192.000000, w: 540.000000, h: 620.000000

最后,为了获得模态视图从屏幕底部的偏移量,我这样做了:

UIView* modalView = self.viewController.view.superview.superview.superview.superview;
// usage of self-explanatory UIView category methods
CGFloat bottomOffset = modalView.superview.height - (modalView.y + modalView.height);

令我懊恼的是,这只适用于纵向模式。出于某种原因,无论 iPad 处于什么方向,模态视图的超级视图总是卡在 768 的宽度和 1024 的高度。所以这就是我寻求帮助的地方。无论方向如何,如何在 iPad 上可靠地获取模式视图从屏幕底部的偏移量?

【问题讨论】:

【参考方案1】:

我看到了两种可能的解决方案:

    使用inputAccessoryView 将文本字段自动附加到键盘。

    将键盘矩形转换为您要移动的 containerView 的父视图。然后,您可以在 containerView 的 superview 的坐标中获取其顶部 Y 值

类似:

CGRect rectInWindowCoordinates = [self.containerView.window convertRect:keyboardRect fromWindow:nil];
CGRect rectCoveredByKeyboard = [self.containerView.superview convertRect:rectInWindowCoordinates fromView:nil];
CGFloat top = CGRectGetMinY(rectCoveredByKeyboard);
self.containerView.y = top - self.containerView.frame.size.height;

【讨论】:

在我花时间实现inputAccessoryView之前,我想知道iPad的Messages App的文本输入框是否也使用inputAccessoryView。该设计与我的设计几乎相同。基本上,UITextFieldinputAccessoryView 是一回事。 UITextField 最初位于屏幕底部,并在键盘出现时向上移动以变为 inputAccessoryView 我猜它没有使用inputAccessoryView,因为它具有特殊的键盘滚动行为。如果您想要与 Messages 界面几乎相同的东西,您可能可以find one on Cocoa Controls 使用或查看示例。 我正在尝试实施您的第二个选项,但是我使用的是UIView convertPoint:(CGPoint)point toView:(UIView*)view。我将UIWindow 中的键盘顶点转换为我的文本字段的坐标系。这在纵向模式下运行良好,但在横向模式下仍然中断。当键盘以横向出现时,它将模态视图推到更高的屏幕顶部。所以最初,我可以将我的文本字段与键盘齐平,但是一旦模态视图滑动得更高,键盘就会覆盖文本字段。 啊,对了!我忘记了。我已经更新了我的答案,以包括应该解决该问题的所需窗口转换。 (键盘矩形是屏幕坐标,不是窗口坐标,所以你必须先转换成窗口坐标。)【参考方案2】:
- (void) onKeyboardShow:(NSNotification *)notification

    CGRect keyboardRect = [[[notification userInfo] 
        objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue
    ];    

    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;

    // The keyboard height is only correct when in portrait mode. To get the
    // real height, we make the assumption that keyboards are always wider than
    // they are tall.
    CGFloat keyboardHeight;
    if (keyboardRect.size.width < keyboardRect.size.height) 
        keyboardHeight = keyboardRect.size.width;
     else 
        keyboardHeight = keyboardRect.size.height;
    

    CGPoint originOfKeyboardInWindowContext;

    switch (orientation) 
        //
        // (0,0) ___________
        //      |           |
        //      |           |
        //      |           |
        //      |           |
        //      |           |
        //      |===========|
        //      |===========|
        //
        case UIInterfaceOrientationPortrait:
            originOfKeyboardInWindowContext = CGPointMake(0.0, [VeetleAppDelegate instance].window.height - keyboardHeight);
            break;
        //
        //       ___________
        //      |           |
        //      |           |
        //      |           |
        //      |           |
        //      |           |
        //      |===========|
        //      |===========| (0,0)
        //
        case UIInterfaceOrientationPortraitUpsideDown:
            originOfKeyboardInWindowContext = CGPointMake(0.0, keyboardHeight);
            break;
        //
        //       _________________
        //      |                 |
        //      |                 |
        //      |                 |
        //      |=================|
        //      |=================|
        // (0,0)
        //
        case UIInterfaceOrientationLandscapeRight:
            originOfKeyboardInWindowContext = CGPointMake(keyboardHeight, 0.0);
            break;
        //
        //       _________________  (0,0)
        //      |                 |
        //      |                 |
        //      |                 |
        //      |=================|
        //      |=================|
        //
        case UIInterfaceOrientationLandscapeLeft:
            originOfKeyboardInWindowContext = CGPointMake([VeetleAppDelegate instance].window.width - keyboardHeight, 0.0);
            break;
    

    CGPoint originOfKeyboardInTextFieldContext = [[VeetleAppDelegate instance].window convertPoint:originOfKeyboardInWindowContext toView:self.containerView.superview];

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
    self.containerView.y = originOfKeyboardInTextFieldContext.y - self.containerView.height;
    [UIView commitAnimations];

【讨论】:

以上是关于如何计算 iPad 上模态视图的底部偏移量?的主要内容,如果未能解决你的问题,请参考以下文章

显示键盘时在 iPad 上的表单中调整表格视图的大小

什么是偏移量 怎么计算

动态计算偏移量

如何获取滚动视图内容偏移量?

贝加莱PLC。写入后计算新偏移量或如何将数据写入新行

如果数组大小发生变化以及定义的宏如何在此处计算偏移量,为啥 C 结构中的字符数组的偏移量会有所不同? [复制]