UIScrollView的内容偏移被重置

时间:2012-02-14 03:40:48

标签: ios uiscrollview

我一直在努力解决UIScrollView的问题。

我有一个UIScrollVIew,其中包含UITextView作为子视图。当我选择文本视图时,会弹出一个键盘。我想调整文本视图的大小以完全适合可用空间,并且还滚动滚动视图,以便文本视图完全位于可见空间中(不会被键盘隐藏)。

当键盘出现时,我调用一个方法来计算文本视图的适当大小,然后执行以下代码:

[UIView animateWithDuration:0.3 
                 animations:^
 { 
     self.textView.frame = frame;
 }  
 ];

[self.scrollView setContentOffset:CGPointMake(0,frame.origin.y) animated:YES];

(此处框架是文本视图的适当框架)。

不幸的是,滚动视图并不总是滚动到正确的位置,尤其是当我选择文本视图时,它已经处于非零垂直内容偏移。我知道我设置的内容偏移是正确的。

经过大量测试后,我终于意识到发生的事情是动画完成后,滚动视图会自动滚动。

此代码确实有效:

UIView animateWithDuration:0.3 
                 animations:^
 { 
     self.textView.frame = frame;
 }
 completion:^(BOOL finished) {
     [self.scrollView setContentOffset:CGPointMake(0, frame.origin.y) animated:YES];
 }
 ];

但它看起来很奇怪,因为滚动视图滚动到错误的位置,然后滚动到右边的位置。

当文本视图框完成动画时,是否有人知道如何阻止滚动视图更改内容偏移?

我正在使用iOS 5.0进行测试。


这是我发现有效的解决方案。我仍然不完全理解发生了什么,可能与我的弹簧和支柱的设置方式有关。基本上我将滚动视图内容大小缩小了与文本视图缩小相同的量。

- (void)keyboardDidShow:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];

    // Get the height of the keyboard
    CGRect kbRect = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
    kbRect = [self.view convertRect:kbRect fromView:nil];
    CGSize kbSize = kbRect.size;

    // Adjust the height of the text view to fit in the visible view
    CGRect frame = self.textView.frame;
    int visibleHeight = self.view.frame.size.height;
    visibleHeight -= kbSize.height;
    frame.size.height = visibleHeight;

    // Get the new scroll view content size
    CGSize contentSize = self.scrollView.contentSize;
    contentSize.height = contentSize.height - self.textView.frame.size.height + frame.size.height;

    [UIView animateWithDuration:0.1 
                     animations:^
     { 
         self.textView.frame = frame;
         // Note that the scroll view content size needs to be reset, or the scroll view
         // may automatically scroll to a new position after the animation is complete.
         self.scrollView.contentSize = contentSize;
         [self.scrollView setContentOffset:CGPointMake(0, frame.origin.y) animated:YES];
     }     
     ];

    // Turn off scrolling in scroll view
    self.scrollView.scrollEnabled = NO;
}

// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    // Update the view layout
    [UIView animateWithDuration:0.3 animations:^
     {
         self.scrollView.contentOffset = CGPointZero;
         [self updateViewLayout];
     }
     ];

    // Turn on scrolling in the scroll view
    self.scrollView.scrollEnabled = YES;
}

[self updateViewLayout]是一种将文本视图返回到正确高度的方法,并重置滚动视图内容大小,并确保所有其他子视图都已正确定位。

4 个答案:

答案 0 :(得分:3)

不要调整文本视图的框架。您需要做的就是滚动滚动视图。如果滚动滚动视图动画,则textView将向上滑动动画。只需执行以下操作:

[self.scrollView setContentOffset:CGPointMake(0, frame.origin.y) animated:YES];

如果你需要滚动视图以特定的速率滚动,那么手动调整动画块中的内容偏移量。(我没有测试过这个,你可能想要调整动画标记,或者逐步调整内容偏移量如果这不起作用,一次只有像素)

[UIView animateWithDuration:0.3f 
             animations:^{ 
  [self.scrollView setContentOffset:CGPointMake(0, frame.origin.y) animated:YES];
} ];

答案 1 :(得分:3)

我相信我也有类似的东西。我希望我的水平UIScrollView回到它的原始偏移量(0,0),每次我回到它的动画时,它只会关闭几个像素,但只要有人触摸了滚动视图,它就会继续并完成动画(几乎像电子游戏中的滞后)。

由于这个原因,我尝试将它作为主队列放在GCD中,之后它完全正常。这是代码:

- (void)setPageZero{
       dispatch_async(dispatch_get_main_queue(), ^{
       [UIView animateWithDuration:1.0f
                delay:0 options:UIViewAnimationOptionCurveEaseInOut
                animations:^{
                     [self.scrollView setContentOffset:CGPointMake(0, self.scrollView.frame.origin.y) animated:YES];
                 }
           completion:^(BOOL finished) {}];
       });
}

基本上做的是,它将动画放入主队列(有点像CPU / GPU中的高速公路),并将其优先于其他事物!

希望这有助于未来的读者!

答案 2 :(得分:2)

我遇到了类似的问题。基本上我有一个包含三个页面的滚动视图,每个页面包含一个自定义UIView类。自定义UIView类包含一个图像和一些包含图像信息的叠加视图。叠加层视图包含多个UITextView字段。

我将自定义视图附加到滚动视图,然后加载图像&使用块操作叠加。我通过删除第一个视图,重新定位接下来的两个视图以及向右添加新视图来向右滑动。

如果我创建UITextField个对象并禁用滚动,如下所示:

UITextView* view = [[UITextView alloc]
                    initWithFrame:CGRectMake(position.x,position.y,width,height)];
view.editable = NO;  
view.scrollEnabled = NO;

然后当我从块代码返回时,滚动视图在页面之间重新定位。请注意,我没有重新定位滚动视图,在从块退出时,滚动视图位于正确的位置。

但是,如果我注释掉禁用滚动的代码

UITextView* view = [[UITextView alloc]
                    initWithFrame:CGRectMake(position.x,position.y,width,height)];
view.editable = NO;  
// view.scrollEnabled = NO;

这种重新定位不会发生,滚动按预期工作。

答案 3 :(得分:0)

完全破解:可以改善重置问题:

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{        
        [self setContentOffset:self.contentOffset animated:NO];
}