UIScrollView scrollRectToVisible:动画:在iOS7上不考虑rect

时间:2014-01-29 14:56:15

标签: ios iphone objective-c ios7 uiscrollview

[self.scrollView scrollRectToVisible:rect animated:YES];

有没有人知道为什么这在iOS6.1和iOS7.0上完全正常工作总是滚动到已成为firstResponder的UITextField,无论我作为参数发送什么样的矩形?

CGRect rect = CGRectMake(0, self.scrollView.frame.size.height - 1, 320, 1);
[self.scrollView scrollRectToVisible:rect animated:YES];

当显示键盘时,由于UIScrollView内的UITextField已成为iOS6.1上的第一响应者,此代码将UIScrollView滚动到底部,但在iOS7.0.4上滚动它以便UITextFiled可见。

正如我想的那样,iOS7 SDK中的UIScrollView无论如何,当scrollRectToVisible:animated:被调用时,自动滚动到内部的第一个响应者。

5 个答案:

答案 0 :(得分:10)

我怀疑大多数开发人员正在将scrollRectToVisible:Animated:与系统键盘通知结合使用,如Apple Docs here中所述。对我来说,Apple提供的示例代码并没有起作用(好吧,只有一半是这样的。)

将方法调用放在调度块中为我解决了问题:

dispatch_async(dispatch_get_main_queue(), ^{
    [self.scrollView scrollRectToVisible:rect animated:YES];
});

我不完全理解为什么会这样做,我不确定这是否100%安全,但另一方面,感觉比仅仅延迟0.1秒的呼叫更安全{ {3}}

我还不是线程问题的专家(但是)但是当发送UIKeyboardDidShowNotification时,似乎任何隐藏的系统方法都会覆盖滚动行为。因此,如果我们将方法调用放在主队列上,它将在之后执行,从而产生所需的效果。 (但这只是猜测。)

答案 1 :(得分:9)

在iOS 8(可能还有7个)上,操作系统在runloop操作的尾端自动滚动到UITextField,就在它返回到监听用户输入之前。 在OS自动滚动之后和用户输入之前,我没有找到任何方法进入。 UIKeyboardWillShowNotificationUIKeyboardDidShowNotification都不是可行的钩子。

然而,总是有效的是延迟后执行选择器的好老把戏。只需将滚动代码放在自己的方法中,然后调用该方法:

- (void)keyboardDidShow:(NSNotification*)aNotification {
  // ... all code to choose the view you want ...
  [self performSelector:@selector(moveToView:) withObject:visibleView afterDelay:0.1];
}

- (void)moveToView:(UIView *)aView {
  [self.scView scrollRectToVisible:aView.frame animated:YES];
}

这将在操作系统自动滚动后运行,而你是黄金。

答案 2 :(得分:4)

之前我遇到过这个问题。不是一件容易的事,但肯定很无聊。

这是因为我将contentSize设置为0(因为您不希望它滚动)。你应该至少设置1个。

[scrollView setContentSize: CGSizeMake(1, self.view.frame.size.height)];

我希望这是解决方案;)

答案 3 :(得分:2)

我找到了解决这个问题的方法,但它不是一个漂亮的问题。为了将滚动视图滚动到所需位置,您必须同时注册keyboardWillShow和keyboardDidShow通知。然后将用于设置滚动视图的插图的代码放置在keyboardWillShowNotification的观察者的选择器中,并将用于将滚动视图滚动到所需位置的代码放置在keyboardDidShowNotification的观察者'选择器。这就是我所拥有的:

在viewDidLoad中:

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

通知方法:

- (void) keyboardWillShow: (NSNotification*) aNotification;
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
    float kbHeight = kbSize.height < kbSize.width ? kbSize.height : kbSize.width;
    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbHeight, 0.0);
    _scrollView.contentInset = contentInsets;
    _scrollView.scrollIndicatorInsets = contentInsets;
}

-(void)keyboardDidShow:(NSNotification*)notification
{
    CGRect aRect = CGRectMake(0, 0, _scrollView.frame.size.width, _scrollView.frame.size.height - _scrollView.frame.origin.y - self.scrollView.contentInset.bottom);
    CGRect scrollFrame = CGRectMake(self.loginView.frame.origin.x + self.loginButton.frame.origin.x, self.loginView.frame.origin.y + self.loginButton.frame.origin.y, self.loginButton.frame.size.width, self.loginButton.frame.size.height);
    if (!CGRectContainsRect(aRect, scrollFrame)) {
        [_scrollView scrollRectToVisible:scrollFrame animated:YES];
    }
}

答案 4 :(得分:0)

我一直在关注Apple文档,但没有成功。然后,我尝试在自己的scrollView上调用setContentOffset(_:animated:),而不是scrollRectToVisible(_:animated:),这使它起作用。

如果隐藏在键盘下,则下面的代码滚动到myView,假设您收到keyboardWillShow时调用了UIResponder.keyboardWillShowNotification函数。

快速5

@objc private func keyboardWillShow(_ notification: Notification) {
    if let keyboardHeight = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size.height {
            scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardHeight, right: 0)

        let visibleViewFrame = myView.frame
        var scrollViewFrame = scrollView.frame
        scrollViewFrame.size.height -= keyboardHeight

        if !scrollViewFrame.contains(visibleViewFrame) {
            scrollView.setContentOffset(CGPoint(x: 0, y: visibleViewFrame.origin.y), animated: true)
        }
    }
}