- objective-c - iOS 5 : Can you override UIAppearance customisations in specific classes?
- iphone - 如何将 CGFontRef 转换为 UIFont?
- ios - 以编程方式关闭标记的信息窗口 google maps iOS
- ios - Xcode 5 - 尝试验证存档时出现 "No application records were found"
我在一个显示大量照片 (50-200) 的应用程序中使用 UICollectionView
并且我在让它变得活泼时遇到了问题(例如像照片应用程序一样活泼).
我有一个自定义 UICollectionViewCell
和一个 UIImageView
作为它的 subview 。我使用 UIImage.imageWithContentsOfFile:
从文件系统加载图像到单元格内的 UIImageViews。
我现在已经尝试了很多方法,但它们不是有问题就是有性能问题。
注意:我正在使用 RubyMotion,因此我将以 Ruby 风格编写所有代码片段。
首先,这是我自定义的 UICollectionViewCell 类以供引用...
class CustomCell < UICollectionViewCell
def initWithFrame(rect)
super
@image_view = UIImageView.alloc.initWithFrame(self.bounds).tap do |iv|
iv.contentMode = UIViewContentModeScaleAspectFill
iv.clipsToBounds = true
iv.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth
self.contentView.addSubview(iv)
end
self
end
def prepareForReuse
super
@image_view.image = nil
end
def image=(image)
@image_view.image = image
end
end
方法 #1
保持简单..
def collectionView(collection_view, cellForItemAtIndexPath: index_path)
cell = collection_view.dequeueReusableCellWithReuseIdentifier(CELL_IDENTIFIER, forIndexPath: index_path)
image_path = @image_paths[index_path.row]
cell.image = UIImage.imageWithContentsOfFile(image_path)
end
使用这个向上/向下滚动很糟糕。它跳跃而缓慢。
方法 #2
通过 NSCache 添加一点缓存...
def viewDidLoad
...
@images_cache = NSCache.alloc.init
...
end
def collectionView(collection_view, cellForItemAtIndexPath: index_path)
cell = collection_view.dequeueReusableCellWithReuseIdentifier(CELL_IDENTIFIER, forIndexPath: index_path)
image_path = @image_paths[index_path.row]
if cached_image = @images_cache.objectForKey(image_path)
cell.image = cached_image
else
image = UIImage.imageWithContentsOfFile(image_path)
@images_cache.setObject(image, forKey: image_path)
cell.image = image
end
end
同样,在第一个完整卷轴上跳动缓慢,但从那时起就一帆风顺了。
方法 #3
异步加载图像...(并保留缓存)
def viewDidLoad
...
@images_cache = NSCache.alloc.init
@image_loading_queue = NSOperationQueue.alloc.init
@image_loading_queue.maxConcurrentOperationCount = 3
...
end
def collectionView(collection_view, cellForItemAtIndexPath: index_path)
cell = collection_view.dequeueReusableCellWithReuseIdentifier(CELL_IDENTIFIER, forIndexPath: index_path)
image_path = @image_paths[index_path.row]
if cached_image = @images_cache.objectForKey(image_path)
cell.image = cached_image
else
@operation = NSBlockOperation.blockOperationWithBlock lambda {
@image = UIImage.imageWithContentsOfFile(image_path)
Dispatch::Queue.main.async do
return unless collectionView.indexPathsForVisibleItems.containsObject(index_path)
@images_cache.setObject(@image, forKey: image_path)
cell = collectionView.cellForItemAtIndexPath(index_path)
cell.image = @image
end
}
@image_loading_queue.addOperation(@operation)
end
end
这看起来很有希望,但有一个我无法追踪的错误。在初始 View 加载时,所有图像都是相同的图像,并且当您滚动整个 block 时,会加载另一个图像,但所有图像都有该图像。我试过调试它,但我无法弄明白。
我也尝试用 Dispatch::Queue.concurrent.async { ... }
替换 NSOperation,但这似乎是一样的。
如果我能让它正常工作,我认为这可能是正确的方法。
方法 #4
沮丧的是,我决定将所有图像预加载为 UIImages...
def viewDidLoad
...
@preloaded_images = @image_paths.map do |path|
UIImage.imageWithContentsOfFile(path)
end
...
end
def collectionView(collection_view, cellForItemAtIndexPath: index_path)
cell = collection_view.dequeueReusableCellWithReuseIdentifier(CELL_IDENTIFIER, forIndexPath: index_path)
cell.image = @preloaded_images[index_path.row]
end
事实证明,在第一个完整滚动中,这有点缓慢和跳跃,但之后一切都很好。
总结
所以,如果有人能指出正确的方向,我将不胜感激。照片应用如何做到如此出色?
其他人请注意:[接受的] 答案解决了我的图像出现在错误单元格中的问题,但即使在将图像调整为正确尺寸后,我的滚动仍然不稳定。在将我的代码剥离到最基本的部分之后,我最终发现 UIImage#imageWithContentsOfFile 是罪魁祸首。尽管我使用这种方法预热了 UIImages 的缓存,但 UIImage 似乎在内部进行了某种惰性缓存。更新我的缓存预热代码以使用此处详述的解决方案后 - stackoverflow.com/a/10664707/71810 - 我终于拥有了 super 流畅的 ~60FPS 滚动。
最佳答案
我认为方法 #3 是最好的方法,我想我可能已经发现了这个错误。
您在操作 block 中分配给@image
,这是整个 Collection View 类的私有(private)变量。您可能应该更改:
@image = UIImage.imageWithContentsOfFile(image_path)
到
image = UIImage.imageWithContentsOfFile(image_path)
并更改所有对 @image
的引用以使用局部变量。我敢打赌,问题是每次您创建一个操作 block 并分配给实例变量时,您都会替换已经存在的内容。由于操作 block 出队方式的一些随机性,主队列异步回调正在取回相同的图像,因为它正在访问上次分配的 @image
。
本质上,@image
就像操作和异步回调 block 的全局变量。
关于ios - 如何获得包含大量图像(50-200)的活泼的 UICollectionView?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13864958/
我想在使用 Snappy 和 Wkhtmltopdf 生成的每个页面的页脚中显示页码,但我还没有找到任何线索。 我可以设置页脚文本(使用选项“footer-center”)但是如何放置页码? 最佳答案
我是一名优秀的程序员,十分优秀!