UIScrollView图像/照片查看器启用分页和缩放

好吧,我认为是时候在互联网上为这个问题做一个官方的地方:如何使用分页和缩放来制作UIScrollView photoviewer。 欢迎我的同胞UIScrollView黑客。

我有一个启用分页的UIScrollView ,我显示UIImageViews像内置的照片应用程序。 (这听起来很熟悉吗?)

我在github上find了以下项目:

http://wiki.github.com/andreyvit/ScrollingMadness

其中显示了如何在启用分页的情况下在滚动视图中实现缩放。 如果有人试过这个,我实际上已经删除了UIScrollView子类,并使用本地类,否则它不工作。 我认为这是因为3.0 SDK中有关滚动视图如何拦截触摸事件的变化。

所以这个想法是当你开始缩放时删除所有其他视图,并将当前视图移动到(0,0)在scrollview ,更新contentsize等,然后当你放大到1.0f它将其他视图加回并把事情整理回来。

无论如何,该项目在模拟器中完美地工作,但在设备上,有一些令人讨厌的视图移动,这是因为我们正在改变视图大小的contentsize / offset等。 您必须执行此视图移动,否则您可以向左平移其他视图留下的空白。

我在3.0 SDK发行说明的“已知问题”中发现了一个有趣的注释 :

UIScrollView:缩放后,内容插入被忽略,内容被留在错误的位置。

这种声音就像这里发生的一样。 放大之后,视图会偏离屏幕,因为您已经更改了偏移等。

我已经花了数小时的时间,而且我正在减速到一个悲伤的认识,这是不行的。

Three20的照片浏览器是不可能的:它的重量太重,而且有太多不必要的UI和其他行为。

内置的照片应用程序似乎做了一些魔术。 如果放大图像并平移到较远的边缘,当前的照片将独立于旁边的照片移动,这与使用标准UIScrollView尝试不同。

我已经看到了关于嵌套UIScrollView的讨论,但我真的不想去那里。

有没有人用标准的UIScrollViewpipe理这个(在2.2和3.0 SDK中工作)? 我不喜欢滚动我自己的缩放+反弹+平底锅+分页代码。

UPDATE

由于下面的消息,我删除了我以前的答案…

那些没听说过的大新闻。 苹果已经向所有iphone开发者计划的成员发布了2010年WWDC会议video。 讨论的话题之一是他们如何创build照片的应用程序! 他们逐步构build了一个类似的应用程序,并免费提供所有的代码。

它也不使用私人API。 这里是示例代码下载的链接。 您可能需要login才能访问。

选中此项

而且,这里是一个链接到iTunes WWDC页面:

选中此项

我写了一个简单易用的照片浏览器,名为MWPhotoBrowser 。 我决定创build它,因为Three20太重/太臃肿,我只需要一个照片浏览器。

MWPhotoBrowser可以显示一个或多个图像,通过提供UIImage对象,或URL,文件,networking图像或图书馆资产。 照片浏览器可以无缝地处理从网上下载和caching照片。 可以缩放和平移照片,并显示可选(可自定义)的标题。 浏览器也可以用来允许用户使用网格或主图像视图select一个或多个照片。

MWPhotoBrowser截图

你说你已经看过嵌套UIScrollViews的讨论,但不想去那里 – 但这是要走的路! 它工作容易,很好。

这本质上是苹果公司在PhotoScroller的例子中所做的(和2010年的WWDC谈话有关的是Jonah的答案)。 只是在这些例子中,他们增加了一大堆复杂的平铺和其他内存pipe理。 如果你不需要平铺等,如果你不想通过这些例子,尝试删除相关的位,嵌套UIScrollViews的基本原则其实很简单:

  • 创build一个外部的UIScrollView,并设置其pagingEnabled = true。 将它添加到你的主视图,并将其宽度和高度设置为主视图的宽度和高度。

  • 根据需要创build尽可能多的内部UIScrollViews图像。 将它们的宽度和高度设置为主视图的宽度和高度。 把它们作为子视图添加到你的外部UIScrollView中,每一个都紧挨着另一个。

  • 将外部UIScrollView的内容大小并排设置为所有内部UIScrollViews的宽度总和(等于[您的主视图的宽度] * [图像数量])。

  • 将UIImageView添加到内部UIScrollViews,将一个UIImageView添加到每个内部UIScrollView。 将每个UIScrollView的内容大小设置为每个UIImageView的大小。

  • 为每个内部UIScrollView设置最小和最大缩放比例,并将每个内部UIScrollView的委托设置为您的视图控制器。 在委托的viewForZoomingInScrollView中,为传递的UIScrollView返回适当的UIImageView。 (要做到这一点,只需将每个UIImageView保存在一个NSArray中,并将相应的UIScrollView的标签属性设置为适当的UIImageView的索引即可,然后读取传递给viewForZoomingInScrollView的UIScrollView中的标签,并从NSArray返回相应的UIImageView) 。

而已。 就像照片应用程序一样工作。

如果你有很多照片,为了节省内存,你可以有两个内部的UIScrollViews和两个UIImagesViews。 然后,您在它们之间dynamic翻转,在外部UIScrollView中移动它们的位置,并在用户滚动外部UIScrollView时更改它们的图像。 这有点复杂,但原理相同。

我做了一些玩本土的照片应用程序,我想我可以有信心地说,他们正在使用一个单一的UIScrollView。 赠品是这样的:放大图像,并向左或向右拉。 你会看到下一张或上一张照片。 如果你足够的拖拽,它甚至可以在1.0f变焦的情况下翻到下一张照片。 翻转和以前缩放的照片将回到1.0f放大以及。

很明显,我没有写Photos.app,但我会大胆猜测他们是如何做到的:

  • 一个UIScrollView和一个UIScrollViewDelegate
  • 用UIImageView子元素填充UIScrollView
  • 监听scrollViewDidScroll:
  • 做一些math计算 ,找出你目前的页面
  • 听取viewForZoomingInScrollView:
  • 根据页面索引返回不同的视图
  • scrollViewDidEndZooming:withView:atScale:并根据内容select做一些反锯齿等

如果你决定尝试一下,让我知道它是如何解决你的。 我很想知道你是如何最终得到这个工作的。 更好的是,发布到github。

我做了一些玩本土的照片应用程序,我想我可以有信心地说,他们正在使用一个单一的UIScrollView。 赠品是这样的:放大图像,并向左或向右拉。 你会看到下一张或上一张照片。 如果你足够的拖拽,它甚至可以在1.0f变焦的情况下翻到下一张照片。 翻转和以前缩放的照片将回到1.0f放大以及。

这是错误的。 我使用嵌套滚动视图,并得到完全相同的效果。 如果你正在使用一些内存pipe理scheme(我不得不开始使用…我的页面数量相当高(在两个scrollView中都是50),那么你可以使用类似于你触发页面的机制加载/卸载从当前页面触发页面-1和+1的缩放重置。

我怀疑苹果在前一张照片消失后立即closures。

我不明白的是如何实现页面之间的平滑滚动 – 在转换时总是有一个很短的挂起。 不明白。 我已经深入修复它–NSInvocationOperations是我的第一站,然后我做了一个可重用的视图队列的页面浏览量(保留他们的形象意见)…仍然这停顿了。

我只有一个NSOperationQueue正在运行,而且我试过摆弄最大并发操作数。 我的想法是主线程被竞争队列阻塞,或者甚至有一个队列试图做很多…仍然是挂起。

我甚至尝试创build我的媒体的超低版本,以防万一这是问题。 每张图片的重量都在10K左右(这些是jpegs,介意你)……你猜对了。 这个挂钩还在那里。

我几乎决心做我以前做的事情,并从Three20使用TTPhotoViewController。 我已经花了几个小时在代码中游泳了,这总是一个很好的教育。 不过,在这一点上,我真的很想知道这个挂钩从哪里来,如果只是这样,我可以把我睡不着觉的时间花在脑海里沸腾的东西上。

如果苹果在照片应用程序中构build了一个图片浏览器,我们就可以使用。 我目前正在使用three20,它很好。 但是,当你真正想要的是照片浏览器时,还需要额外的东西。

我写了一个代码,可以作为参考

  1. 加载当前视图的scrollview和imageview ..以及当前视图旁边的屏幕,只有imageview

  2. 删除当前页面加载时的所有视图以节省内存,这对很多照片项目都是好的

  3. 使用标签来区分不同的滚动视图

第一页 _xxxx 滑动 XXX 放大

下载链接点击这里