我使用UICollectionView
在相当展示了许多照片(50-200)的应用程序,我有得到它的问题是活泼的(如活泼,例如照片应用程序)。
我有一个自定义UICollectionViewCell
用UIImageView
,因为它的子视图。 我从文件系统加载图像,与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
这看起来很有前途,但没有,我不能追查的错误。 在初始视图加载所有的图像是相同的图像,将滚动与其它图像整块负载,但都有这样的形象。 我试着调试它,但我不能弄明白。
我也试着代与的NSOperation Dispatch::Queue.concurrent.async { ... }
但似乎是相同的。
我想,这可能是正确的做法,如果我能得到它的正常工作。
办法#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 -我终于有超光滑〜60FPS滚动。