ios UIScrollView 的内容偏移被重置

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9271391/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 16:50:42  来源:igfitidea点击:

UIScrollView's content offset being reset

iosuiscrollview

提问by Darren

I have been struggling for a long time with a problem with a UIScrollView.

我一直在为 UIScrollView 的问题苦苦挣扎。

I have a UIScrollVIewthat contains a UITextViewas a subview. When I select the text view a keyboard pops up. I want to resize the text view to fit exactly in the available space, and also scroll the scroll view so that the text view is positioned exactly in the visible space (not hidden by the keyboard).

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

When the keyboard appears I call a method that calculates the appropriate size for the text view and then performs the following code:

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

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

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

(here frame is the appropriate frame for the text view).

(这里的框架是文本视图的合适框架)。

Unfortunately the scroll view does not always scroll to the correct position, especially when it is already at a non zero vertical content offset when I select the text view. I know that the content offset that I'm setting it to is correct.

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

After a lot of testing I finally realized that what was happening was that after the animation completed, the scroll view was automatically scrolling again.

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

This code does work:

此代码确实有效:

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

but it looks strange because the scroll view scrolls to the wrong position, then to the right one.

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

Does anyone know how I can prevent the scroll view from changing it's content offset when the text view frame finishes its animation?

有谁知道当文本视图框架完成其动画时如何防止滚动视图更改其内容偏移量?

I am testing using iOS 5.0.

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



Here is a solution that I found that works. I'm still don't completely understand what's happening, possible it has something to do with the way my springs and struts are set. Basically I am shrinking the scroll view content size by the same amount that the text view shrinks.

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

- (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]is a method that returns the text view to the correct height, and resets the scroll view content size, as well as making sure all the other subviews are properly positioned).

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

回答by Hyman Freeman

Do not adjust the frame of the text view. All you need to do is scroll the scrollview. If you scroll the scrollview animated, then the textView will slide up animated. Just do the following:

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

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

If you need the scroll view to scroll at a specific rate then manually adjust the content offset in an animation block.(I haven't tested this, you may want to adjust the animation flag, or step through the content offset one pixel at a time if this doesn't work)

如果您需要滚动视图以特定速率滚动,则手动调整动画块中的内容偏移量。(我还没有测试过这个,您可能想要调整动画标志,或者以一个像素为单位逐步调整内容偏移量时间,如果这不起作用)

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

回答by sridvijay

I believe I also had something similar. I wanted my horizontal UIScrollView to go back to it's original offset (0,0), and every time I animated back to it, it would be just a couple pixels off, but as soon as someone touched the scrollview, it would continue and finish the animation (almost like lag in a video game).

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

Due to that, I tried putting it in GCD as the main queue and it worked perfectly fine after that. Here's the code:

因此,我尝试将它放在 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) {}];
       });
}

What that basically does, is that it puts the animation into the main queue (kind of like a superhighway in the CPU/GPU) and it prioritizes it over other things!

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

Hope this helps future readers!

希望这对未来的读者有所帮助!

回答by David Gray

I'm having a similar problem. Basically I have a scroll view with three pages each containing a custom UIViewclass. The custom UIViewclass contains an image and a number of overlay views containing information about the image. The overlay views contain a number of UITextViewfields.

我有类似的问题。基本上我有一个包含三个页面的滚动视图,每个页面包含一个自定义UIView类。自定义UIView类包含一个图像和许多包含有关图像信息的覆盖视图。覆盖视图包含许多UITextView字段。

I attach the custom views to the scroll view and then I load the image & overlays using block operations. I swipe to the right by deleting the first view, repositioning the next two views, and adding an new view to the right.

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

If I create the UITextFieldobjects and disable scrolling as follows:

如果我创建UITextField对象并禁用滚动如下:

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

Then the scroll view gets repositioned between pages when I return from the block code. Note that I don't reposition the scroll view and on exit from the block, the scroll view is in the correct position.

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

However, if I comment out the code to disable scrolling

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

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

this repositioning does not occur and the scrolling works as expected.

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

回答by Vlad

Complete hack: May improve the reset issue:

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

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