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]
是一种方法,它将文本视图返回到正确的高度,并重置滚动视图内容大小,并确保所有其他子视图都正确定位)。
I have been struggling for a long time with a problem with a UIScrollView.
I have a UIScrollVIew
that contains a UITextView
as 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).
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.
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).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
不要调整文本视图的框架。您所需要做的就是滚动滚动视图。如果你滚动滚动视图动画,那么文本视图将向上滑动动画。只需执行以下操作:
如果您需要滚动视图以特定速率滚动,则手动调整动画块中的内容偏移量。(我还没有测试过这一点,您可能需要调整动画标志,或单步执行内容如果这不起作用,则一次偏移一个像素)
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:
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)
我相信我也有类似的事情。我希望我的水平 UIScrollView 返回到它的原始偏移量 (0,0),每次我动画回到它时,它只会偏离几个像素,但是一旦有人触摸滚动视图,它就会继续并完成动画(几乎就像视频游戏中的滞后)。
因此,我尝试将其放入 GCD 作为主队列,之后它工作得非常好。代码如下:
它的基本作用是将动画放入主队列(有点像 CPU/GPU 中的高速公路),并将其优先于其他事物!
希望这对未来的读者有所帮助!
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).
Due to that, I tried putting it in GCD as the main queue and it worked perfectly fine after that. Here's the code:
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!
Hope this helps future readers!
我也有类似的问题。基本上,我有一个包含三个页面的滚动视图,每个页面包含一个自定义
UIView
类。自定义UIView
类包含一个图像和许多包含图像信息的覆盖视图。覆盖视图包含许多UITextView
字段。我将自定义视图附加到滚动视图,然后加载图像和图像。使用块操作进行叠加。我向右滑动,删除第一个视图,重新定位接下来的两个视图,然后在右侧添加一个新视图。
如果我创建
UITextField
对象并禁用滚动,如下所示:那么当我从块代码返回时,滚动视图将在页面之间重新定位。请注意,我不会重新定位滚动视图,并且在退出块时,滚动视图位于正确的位置。
但是,如果我注释掉代码以禁用滚动,
则不会发生此重新定位,并且滚动会按预期工作。
I'm having a similar problem. Basically I have a scroll view with three pages each containing a custom
UIView
class. The customUIView
class contains an image and a number of overlay views containing information about the image. The overlay views contain a number ofUITextView
fields.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
UITextField
objects and disable scrolling as follows: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
this repositioning does not occur and the scrolling works as expected.
完整破解:可以改善重置问题:
Complete hack: May improve the reset issue:
如果直接在 contentSize 中分配一些值,contentOffset 将被重置 (0, 0)。
相反,请使用 contentLayoutGuide 告诉scrollView contentSize 的大小。
If you assign directly in contentSize some value, contentOffset will be reset (0, 0).
Instead, tell scrollView how contentSize is by using contentLayoutGuide.