【问题标题】:UIScrollView Content Insets not working for Keyboard HeightUIScrollView 内容插图不适用于键盘高度
【发布时间】:2013-05-23 03:25:03
【问题描述】:

当键盘隐藏UITextField 时,我试图通过使用contentInsets 更改大小来移动UIScrollView,如图所示。

但是,它不适用于键盘高度。键盘高度为 216,但如果我将底部插图设置为 iPhone 纵向模式的 515 和 iPhone 横向模式的 310,它只会在正确的位置停止滚动。为什么这些维度会如此不同?我不想硬编码这些任意值。

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.view.frame = self.parentViewController.view.frame;

    [self.textView becomeFirstResponder];

    NSLog(@"scrollview: %f,%f, parent: %f,%f", self.view.frame.size.height, self.view.frame.size.width, self.parentViewController.view.frame.size.height, self.parentViewController.view.frame.size.width);

    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWasShown:)
                                             name:UIKeyboardDidShowNotification
                                           object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillHide:)
                                             name:UIKeyboardWillHideNotification
                                           object:nil];
}

- (void)keyboardWasShown:(NSNotification *)notification
{
    if([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPhone) {

        // Step 1: Get the size of the keyboard.
        CGFloat keyboardHeight = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size.height;

        // Step 2: Adjust the bottom content inset of your scroll view by the keyboard height.
        UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardHeight, 0.0);
        ((UIScrollView*)self.view).contentInset = contentInsets;
        ((UIScrollView*)self.view).scrollIndicatorInsets = contentInsets;

        // Step 3: Scroll the target text field into view.
        CGRect aRect = self.view.frame;
        aRect.size.height = aRect.size.height - keyboardHeight;
        if (!CGRectContainsPoint(aRect, self.textView.frame.origin) ) {
            CGPoint scrollPoint = CGPointMake(0.0, self.textView.frame.origin.y - keyboardHeight);
            [((UIScrollView*)self.view) setContentOffset:scrollPoint animated:YES];
        }
    }
}

- (void) keyboardWillHide:(NSNotification *)notification {
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    ((UIScrollView*)self.view).contentInset = contentInsets;
    ((UIScrollView*)self.view).scrollIndicatorInsets = contentInsets;
}

编辑:

在键盘打开之前,我打印出来:

NSLog(@"scrollview: %f,%f, parent: %f,%f", self.view.frame.size.height, self.view.frame.size.width, self.parentViewController.view.frame.size.height, self.parentViewController.view.frame.size.width);

它会打印这个:

scrollview: 431.000000,320.000000, parent: 431.000000,320.000000

【问题讨论】:

  • 在没有键盘的情况下滚动正常,可能您给定的高度大于父视图的高度。
  • 是的。滚动很好
  • 在打开键盘之前我想知道scrollview的frame和它的父view frame。
  • UIScrollView 在 UITabBarController 中。请查看我的编辑。
  • 在你的代码中是 self.view 是一种滚动视图?

标签: ios uiscrollview


【解决方案1】:

我认为主要问题是您需要使用UIKeyboardFrameEndUserInfoKey 而不是UIKeyboardFrameBeginUserInfoKey

话虽如此,我已经编写了这个方法的不同版本,即使滚动视图没有放在屏幕底部也可以工作,并且可能更适合你:

请注意,我使用self.activeTextField 而不是self.textField

// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
    // Calculate the frame of the scrollview, in self.view's coordinate system
    UIScrollView *scrollView    = self.scrollView;
    CGRect scrollViewRect       = [self.view convertRect:scrollView.frame fromView:scrollView.superview];

    // Calculate the frame of the keyboard, in self.view's coordinate system
    NSDictionary* info          = [aNotification userInfo];
    CGRect kbRect               = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    kbRect                      = [self.view convertRect:kbRect fromView:nil];

    // Figure out where the two frames overlap, and set the content offset of the scrollview appropriately
    CGRect hiddenScrollViewRect = CGRectIntersection(scrollViewRect, kbRect);
    if (!CGRectIsNull(hiddenScrollViewRect))
    {
        UIEdgeInsets contentInsets       = UIEdgeInsetsMake(0.0,  0.0, hiddenScrollViewRect.size.height,  0.0);
        scrollView.contentInset          = contentInsets;
        scrollView.scrollIndicatorInsets = contentInsets;
    }

    [self scrollToActiveTextField];
}

// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    self.scrollView.contentInset          = UIEdgeInsetsZero;
    self.scrollView.scrollIndicatorInsets = UIEdgeInsetsZero;
}

- (void)scrollToActiveTextField
{
    if (self.activeTextField)
    {
        CGRect visibleRect = self.activeTextField.frame;
        visibleRect        = [self.scrollView convertRect:visibleRect fromView:self.activeTextField.superview];
        visibleRect        = CGRectInset(visibleRect, 0.0f, -5.0f);
        [self.scrollView scrollRectToVisible:visibleRect animated:YES];
    }
}

【讨论】:

  • 以前我试图操纵滚动视图的框架来实现这一点,但使用contentInset 使代码更简单。
  • @chakrit 很高兴这对您有所帮助!
  • 如果你在试图弄清楚为什么 scrollRectToVisible 不起作用,Apple 似乎已经改变了一些东西(至少在我的模拟器中的 iOS 8 中)如果矩形在 UITableView 之外, UICollectionView 或 UIScrollView 内容框架,它甚至不费心尝试滚动到它。例如,我调用了 [self.activeField convertRect:self.activeField.frame toView:self.tableView] 但它应该是 [self.activeField.superview convertRect:self.activeField.frame toView:self.tableView],所以rect.origin.x 大约是 500,大于 320,所以它不会滚动。
  • 这是有史以来最伟大的答案之一。这是一个常见问题,但在 Google 中搜索“键盘隐藏 UITextField”之类的内容无法显示此答案。
【解决方案2】:

在代码中创建滚动视图时,将滚动视图的委托设置为自我

 ((UIScrollView*)self.view).delegate=self;

然后

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.view.frame = self.parentViewController.view.frame;

    [self.textView becomeFirstResponder];

    NSLog(@"scrollview: %f,%f, parent: %f,%f", self.view.frame.size.height, self.view.frame.size.width, self.parentViewController.view.frame.size.height, self.parentViewController.view.frame.size.width);

    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWasShown:)
                                             name:UIKeyboardDidShowNotification
                                           object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillHide:)
                                             name:UIKeyboardWillHideNotification
                                           object:nil];
}

- (void)keyboardWasShown:(NSNotification *)notification
{
    if([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPhone) {

        // Step 1: Get the size of the keyboard.
        CGFloat keyboardHeight = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size.height;

        // Step 2: Adjust the bottom content inset of your scroll view by the keyboard height.
        UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardHeight, 0.0);
        ((UIScrollView*)self.view).contentInset = contentInsets;
        ((UIScrollView*)self.view).scrollIndicatorInsets = contentInsets;

        ((UIScrollView*)self.view).scrollEnabled=YES;
    }
}

- (void) keyboardWillHide:(NSNotification *)notification {
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    ((UIScrollView*)self.view).contentInset = contentInsets;
    ((UIScrollView*)self.view).scrollIndicatorInsets = contentInsets;
    [((UIScrollView*)self.view) setContentOffset:CGPointMake(0.0f, 0.0f) animated:TRUE];
    ((UIScrollView*)self.view).contentSize = CGSizeMake(((UIScrollView*)self.view).contentSize.width, ((UIScrollView*)self.view).contentSize.height);
    ((UIScrollView*)self.view).scrollEnabled=NO;

}

#pragma mark - set scrollView content position
-(void)scrollViewToCenterOfScreen:(UIView *)theView
{
    CGFloat theViewY = theView.center.y;
    CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame];
    CGFloat avaliableHeight = applicationFrame.size.height - 300;
    CGFloat y = theViewY - avaliableHeight / 2.0;
    if(y<0)
        y = 0;
    [((UIScrollView*)self.view) setContentOffset:CGPointMake(0,y) animated:YES];
}

#pragma -mark UITextField Delegate methods

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
    [self scrollViewToCenterOfScreen:textField];
    return YES;
}

现在设置您的文本字段的委托。每当 textFieldShouldBeginEditing: 你的滚动视图自动移动。 scrollViewToCenterOfScreen:方法将您的滚动视图位置设置在文本文件位置。

它肯定会设置您的滚动视图内容插图以及 setContentOffset。如果您仍然面临这个问题,请告诉我。谢谢

【讨论】:

  • 嗨 Chandan,问题不在于它没有设置插图——我可以手动设置它们。问题是我无法从屏幕上的任何其他元素中找出正确的高度来设置它们。我正在使用任意数字作为高度。
  • 嗨克里斯汀。抱歉回复晚了。你的问题解决了吗?请让我知道,以便我澄清一下。谢谢
  • 我没有 - 我们仍在硬编码它
  • 嗨,Kristin,让我试试,然后我会给你一个正确的答案
  • 嗨,克里斯汀,我再次更新了我的代码,为您提供更好的解决方案来动态设置滚动位置和 setContentOffset
猜你喜欢
  • 2019-06-15
  • 2016-10-21
  • 1970-01-01
  • 2018-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多