在UIScrollView中设置zoomScale动画时不需要的滚动 [英] Unwanted scrolling when animating zoomScale in UIScrollView

查看:195
本文介绍了在UIScrollView中设置zoomScale动画时不需要的滚动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

执行摘要:
有时 UIScrollView contentOffset的值进行不必要的更改,从而导致应用程序在正在查看的文档中显示错误的位置。不必要的更改与滚动视图的 zoomScale 的动画更改一起发生。

Executive Summary: At times UIScrollView makes an unwanted change to the value of contentOffset, thus causing the app to display the wrong location in the document being viewed. The unwanted change happens in conjunction to an animated change to the scroll view's zoomScale.

详细信息:
我在 UIScrollView 中使用 CATiledLayer 缩小时遇到问题。 CATiledLayer 持有pdf,当 contentOffset 在一定范围内时,当我缩小时,<$ c在缩放发生之前,$ c> contentOffset 被更改(这是错误)。 Apple的代码中似乎更改了 contentOffset

The Details: I'm having trouble when zooming out with CATiledLayer in a UIScrollView. The CATiledLayer holds a pdf, and when contentOffset is within a certain range, when I zoom out, the contentOffset is changed (that's the bug) before the zooming occurs. The contentOffset seems to be changed in Apple's code.

为了说明问题,我修改了Apple的示例应用程序ZoomingPDFViewer 。代码在github上: https://github.com/DirkMaas/ZoomingPDFViewer-bug

To illustrate the problem, I modified Apple's sample app, ZoomingPDFViewer. The code is on github: https://github.com/DirkMaas/ZoomingPDFViewer-bug

点击将导致 zoomScale 更改为0.5,使用 animateWithDuration ,因此缩小。如果 UIScrollView contentOffset.y 小于约2700或大于5900,则 zoomScale 动画效果很好。如果在 contentOffset.y 介于这两个值之间时发生了点击, contentOffset.y 将跳转(不是动画)到大约2700,然后会出现 zoomScale 动画,但会同时进行滚动,这样当动画完成时, contentOffset .y 应该在哪里。但是跳转来自哪里?

A tap will cause zoomScale to be changed to 0.5, using animateWithDuration, thus zooming out. If the UIScrollView's contentOffset.y is less than about 2700 or greater than 5900, the zoomScale animation works fine. If the tap happens when contentOffset.y is between those two values, the contentOffset.y will jump (not animated) to about 2700, and then the zoomScale animation will occur, but scrolling will occur at the same time, so that when the animation is done, the contentOffset.y is where it should be. But where does the jump come from?

例如,当屏幕显示为 contentOffset.y 时为2000点击: zoomScale 动画效果很好; contentOffset.y 未更改。

For example, say the contentOffset.y is 2000 when the screen is tapped: the zoomScale animation works just fine; contentOffset.y is not changed.

但如果 contentOffset.y 为4000: contentOffset.y 将跳转到没有动画,大约2700,然后缩放和滚动将从该点开始同时发生。当动画完成时,看起来好像我们从4000直接缩放,所以我们最终在正确的位置,但行为是错误的。

But if the contentOffset.y is 4000 when the screen is tapped: the contentOffset.y will jump, without animation, to about 2700, and then zooming and scrolling will begin from that point and occur at the same time. When the animation is done, it looks as if we zoomed straight back from 4000, so we end up in the right place, but the behavior is wrong.

关于用户界面:


  • 文本可以正常方式垂直滚动

  • 文本可以是通过正常方式捏合放大和缩小

  • 单击将导致 zoomScale 设置为0.5;更改是动画的

  • the text can be scrolled vertically in the normal way
  • the text can be zoomed in and out by pinching in the normal way
  • a single tap will cause the zoomScale to be set to 0.5; the change is animated

我注意到如果 zoomScale 大于0.5,跳跃不是那么大。另外,如果我使用 setZoomScale:animated:而不是 animateWithDuration ,则该错误消失,但我无法使用它因为我需要链接动画。

I've noticed that if zoomScale is greater than 0.5, the jump is not so big. Also, if I use setZoomScale:animated: instead of animateWithDuration, the bug disappears, but I can't use it because I need to chain animations.

以下是我所做的总结(github中的代码包括这些更改):

Here is a summary of what I did (the code in github includes these changes):



  • 下载ZoomingPDFViewer http://developer.apple.com/library/ios/#samplecode/ZoomingPDFViewer/Introduction/Intro.html 并在XCode中打开它

  • 已更改构建设置|架构|基础SDK到最新的iOS(iOS 4.3)改变了Build Settings | GCC 4.2 - 语言|编译来源Objective-C ++

  • 从项目中删除了TestPage.pdf

  • 将whoiam 5 24 cropped 3-2.pdf添加到项目取代

  • 添加 PDFScrollView * scrollView; ZoomingPDFViewerViewController class

  • 更改 loadView ZoomingPDFViewerViewController 中初始化 scrollView 而不是 sv

  • 已添加 viewDidLoad handleTapFrom:识别器 zoomOut 在PDFScrollview.m中的ZoomingPDFViewerViewController / li>
  • 注释掉 scrollViewDidEndZooming:withView:atScale scrollViewWillBeginZooming:withView:因为他们做图像背景中的东西,分散了手头的问题

  • Downloaded ZoomingPDFViewer from http://developer.apple.com/library/ios/#samplecode/ZoomingPDFViewer/Introduction/Intro.html and opened it in XCode
  • Changed Build Settings | Architectures | Base SDK to Latest iOS (iOS 4.3) changed Build Settings | GCC 4.2 - Language | Compile Sources As to Objective-C++
  • removed TestPage.pdf from the project
  • added "whoiam 5 24 cropped 3-2.pdf" to the project in its place
  • added PDFScrollView *scrollView; to ZoomingPDFViewerViewController class
  • changed loadView in ZoomingPDFViewerViewController to initialize scrollView instead of sv
  • added viewDidLoad, handleTapFrom:recognizer and zoomOut to ZoomingPDFViewerViewController in PDFScrollview.m
  • commented out scrollViewDidEndZooming:withView:atScale and scrollViewWillBeginZooming:withView: because they do stuff in the image background that distracts from the issue at hand

非常感谢对我的支持,以及任何和所有的帮助!

Thanks so much for bearing with me, and any and all help!

推荐答案

最棘手的事情之一了解缩放是因为它总是发生在一个叫做锚点的点附近。我认为理解它的最好方法是想象一个坐标系统层叠在另一个上面。说A是你的外部坐标系,B是内部(B是滚动视图)。当B的偏移为(0,0)且标度为1.0时,则点B(0,0)对应于A(0,0),并且通常B(x,y)= A(x,y) )。

One of the trickiest things to understand about zooming is that it always happens around a point called the Anchor Point. I think the best way to understand it is to imagine one coordinate system layered on top of another. Say A is your outer coordinate system, B is the inner (B will be the scrollview). When the offset of B is (0,0) and the scale is 1.0, then the point B(0,0) corresponds to A(0,0), and in general B(x,y) = A(x,y).

此外,如果B的偏移是(xOff,yOff)则B(x,y)= A(x-xOff,y-yOff)。同样,这仍然假设缩放比例是1.0。

Further, if the offset of B is (xOff, yOff) then B(x,y) = A(x - xOff, y - yOff). Again, this is still assuming zoom scale is 1.0.

现在,再次让偏移为(0,0)并想象当你尝试缩放时会发生什么。屏幕上必须有一个点在缩放时不移动,并且每个其他点从该点向外移动。这就是锚点定义的内容。如果您的锚点是(0,0),则左下角点将保持固定,而所有其他点向上和向右移动。在这种情况下,偏移量保持不变。

Now, let the offset be (0,0) again and imagine what happens when you try to zoom. There must be a point on the screen that doesn't move when you zoom, and every other point moves outward from that point. That is what the anchor point defines. If your anchor is (0,0) then the bottom left point will remain fixed while all other points move up and to the right. In this case the offset remains the same.

如果你的锚点是(0.5,0.5)(锚点被标准化,即0到1,那么0.5是一半然后中心点保持固定,而所有其他点向外移动。这意味着必须改变偏移以反映这一点。如果它在纵向模式的iPhone上,并且您缩放到2.0,则锚点x值将移动屏幕宽度的一半,320/2 = 160。

If your anchor point is (0.5, 0.5) (the anchor point is normalized, i.e. 0 to 1, so 0.5 is half way across), then the center point stays fixed while all other points move outward. This means the offset has to change to reflect that. If it's on an iPhone in portrait mode and you zoom to scale 2.0, the anchor point x value will move half the screen width, 320/2 = 160.

实际滚动视图内容视图在屏幕上的位置由偏移量和锚点定义。因此,如果您只是更改下面的图层锚点而不对偏移进行相应的更改,您将看到视图似乎跳转到其他位置,即使偏移量相同。

The actual position of the scroll views content view on screen is defined by BOTH the offset and the anchor point. So, if you simply change the layers anchor point underneath without making a corresponding change to the offset, you will see the view appear to jump to a different location, even though the offset is the same.

我猜这是潜在的问题。在为缩放设置动画时,Core Animation必须选择一个新的锚点,以便缩放看起来正确。这也将改变偏移量,以便屏幕上的视图实际可见区域不会跳跃。尝试在整个过程中的不同时间记录锚点的位置(它是在您使用Viewslayer属性访问的任何View的基础CALayer上定义的。)

I am guessing that this is the underlying problem here. When you are animating the zoom, Core Animation must be picking a new anchor point so the zooming "looks" right. This will also change the offset so that the views actual visible region on screen doesn't jump. Try logging the location of the anchor point at various times throughout this process (it is defined on the underlying CALayer of any View which you access with a Views "layer" property).

另请参阅文档此处对于漂亮的图片,可能比我在这里给出的情况描述要好得多:)

Also, please see the documentation here for pretty pictures and likely a far better description of the situation than I've given here :)

最后,这里有一段我​​用过的代码片段应用程序更改图层的锚点而不在屏幕上移动。

Finally, here is a snippet of code I used in an app to change the anchor point of a layer without it moving on screen.

-(CGPoint)setNewAnchorPointWithoutMoving:(CGPoint)newAnchor {
    CGPoint currentAnchor = CGPointMake(self.anchorPoint.x * self.contentSize.width,
                                        self.anchorPoint.y * self.contentSize.height);

    CGPoint offset = CGPointMake((1 - self.scale) * (currentAnchor.x - newAnchor.x),
                                 (1 - self.scale) * (currentAnchor.y - newAnchor.y));


    self.anchorPoint = CGPointMake(newAnchor.x / self.contentSize.width,
                                   newAnchor.y / self.contentSize.height);

    self.position = CGPointMake(self.position.x + offset.x, self.position.y + offset.y);

    return offset;
}

这篇关于在UIScrollView中设置zoomScale动画时不需要的滚动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆