为UIScrollView实现自定义缩放

3
我有一个UIScrollView,要求在缩放时contentSize.height应保持不变。例如,从200x100缩放到400x100应该得到新的contentSize为400x100而不是400x200。我希望在用户缩放时进行自己的绘制。
我认为无法使用UIScrollView的正常缩放行为来实现这一点,因此我正在尝试自己编写代码。(我可以让它完成其工作,然后在-scrollViewDidEndZooming:withView:atScale:被调用时重新绘制我的内容,但这并不美观。)
目前,我正在子类化UIScrollView,并尝试在屏幕上有两个手指时进行自己的缩放。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    if ([touches count] != 2) {
        [super touchesMoved:touches withEvent:event];
    } else {
     // do my own stuff
    }
}

我认为通过重写touchesBegan:withEvent:, touchesMoved:withEvent:, touchesEnded:withEvent:和touchesCancelled:withEvent:方法应该可以解决问题,但事实并非如此。
之前的失败尝试是在滚动视图上放置一个透明视图,并将我不感兴趣的触摸事件发送到滚动视图中。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    if ([touches count] != 2) {
        [self.theScrollView touchesMoved:touches withEvent:event];
    } else {
     // do my own stuff
    }
}

任何帮助都将不胜感激。
谢谢, Thomas
3个回答

3
如果你试图在每一帧的pinch-zooming事件上重绘内容,那么你可能无法保持良好的性能。我建议采用让UIScrollView缩放你的绘图的比例版本,然后在-scrollViewDidEndZooming:withView:atScale:代理方法中重新绘制内容以使其清晰的方法。这是我在我的应用程序中所做的,效果非常好。
在缩放结束时正确调整你的内容视图有一些技巧,我在这个答案中描述了它们。基本上,你需要拦截对内容视图的变换设置,以便在重新绘制内容时将其设置为比例因子1。你还需要跟踪该比例因子,因为UIScrollView不会,并使用该比例因子来调整UIScrollView尝试对你的内容视图应用的变换与后续缩放操作。
你可以使用这种技术的修改来强制在pinch-zooming期间重新绘制你的内容,但在我的测试中,这最终会变得太过卡顿,无法提供良好的用户体验。

好的,谢谢。我会尝试拦截 setTransform: 并在捏合缩放结束时重绘视图。我可能会尝试完全重新绘制我的视图并查看性能如何。今天不能完成,但我会告诉你进展如何。 - Thomas Müller
我进行了一个快速测试,拦截了 setTransform: 方法并尝试每次重绘我的内容视图。你说得对,在设备上由于性能原因,这不是一个选择。我将采用你建议的方法,让 UIScrollView 进行缩放,然后在 -scrollViewDidEndZooming:withView:atScale: 中重新绘制。谢谢。 - Thomas Müller

0
我不确定您的意思是什么:

我认为通过重写touchesBegan:withEvent:, touchesMoved:withEvent:, touchesEnded:withEvent:和 touchesCancelled:withEvent:以这种方式应该会起作用,但实际并没有。

您没有收到事件吗? 您应该收到事件,但我认为您if语句中存在逻辑错误,可能会导致此方法无法正常工作。

if ([touches count] != 2)

这是一个问题,因为两个触摸同时发生的可能性很低。您需要能够处理独立发生的触摸以及用户保持一个手指静止并移动另一个手指的情况。在这些常见的情况下,即使另一个触摸仍然有效,您可能只会在那个NSSet中得到一个触摸。

正确处理触摸的解决方案是记住一些关于哪些触摸进入和离开的信息。请记住,UITouch的地址在整个触摸的生命周期内不会改变,因此您可以安全地比较地址以确保您仍在处理之前相同的触摸,并跟踪其生命周期。

如果您没有收到触摸事件,则完全是另一个问题,您可能需要设置multiTouchEnabled:YES


我是基于《Beginning iPhone 3 Programming》中的一章来编写代码的,其中使用了touches NSSet来访问触摸事件。我没有意识到这个NSSet可能不会在每次调用touchesMoved:withEvent:时包含所有的触摸事件。 - Thomas Müller
我开启了multiTouchEnabled,但UIScrollView似乎在幕后做了一些花哨的事情。它有可能会在自身顶部添加一个新视图来处理所有触摸事件,一旦用户开始滚动或缩放吗?这是我的想法,但我并没有真正花太多时间进一步研究这个理论。 - Thomas Müller

0

我正在尝试做与此相同的事情,我真的希望能够在缩放时重新绘制。在scrollViewDidEndZooming:withView:atScale中修复它并不是很好。

我的方法是在viewForZoomingInScrollView:中传递一个虚拟视图,并读取此虚拟视图的高度,并将实际内容视图的框架设置为所需的任何内容。因为框架发生了变化,这意味着每次都会调用drawRect。在模拟器上看起来还不错,我只是画了几条线。但是我实际上没有设备,所以无法进行适当的测试。

此外,在您的代码中,您有touchesBegan:withEvent:,但然后您将其转发到super touchesMoved:withEvent:而不是touchesBegan:withEvent:


我尝试每次重新绘制我的内容视图,虽然在模拟器中它可以正常工作,但在我的 iPhone 3G 上却完全不能接受。根据我测试的数据,我只绘制了9个CGPaths。不过,我的UIScrollView目前是透明的,这可能对性能有相当大的影响。无论如何,你应该尝试在实际设备上测试你的代码——如果在缩放期间重新绘制速度太慢,我不会感到惊讶。 - Thomas Müller

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接