【发布时间】:2015-01-27 06:49:35
【问题描述】:
使用资产库时,您可以从 ALAssetsGroup 获取专辑的海报图片。使用 Photos Framework (Photo kit) 时如何实现同样的效果?
【问题讨论】:
-
你尝试过什么?发布代码,以便其他用户可以检查。
-
查看 Apple 的示例代码:developer.apple.com/documentation/photokit/…
使用资产库时,您可以从 ALAssetsGroup 获取专辑的海报图片。使用 Photos Framework (Photo kit) 时如何实现同样的效果?
【问题讨论】:
我是这样做的。在方法 cellForRowAtIndexPath: 中,在相册 tableView 中添加以下代码。
目标 C:
PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init];
fetchOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
PHFetchResult *fetchResult = [PHAsset fetchKeyAssetsInAssetCollection:[self.assetCollections objectAtIndex:indexPath.row] options:fetchOptions];
PHAsset *asset = [fetchResult firstObject];
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.resizeMode = PHImageRequestOptionsResizeModeExact;
CGFloat scale = [UIScreen mainScreen].scale;
CGFloat dimension = 78.0f;
CGSize size = CGSizeMake(dimension*scale, dimension*scale);
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:size contentMode:PHImageContentModeAspectFill options:options resultHandler:^(UIImage *result, NSDictionary *info) {
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageView.image = result;
});
}];
斯威夫特 3:
let fetchOptions = PHFetchOptions()
let descriptor = NSSortDescriptor(key: "creationDate", ascending: true)
fetchOptions.sortDescriptors = [descriptor]
let fetchResult = PHAsset.fetchKeyAssets(in: assets[indexPath.row], options: fetchOptions)
guard let asset = fetchResult?.firstObject else {
return
}
let options = PHImageRequestOptions()
options.resizeMode = .exact
let scale = UIScreen.main.scale
let dimension = CGFloat(78.0)
let size = CGSize(width: dimension * scale, height: dimension * scale)
PHImageManager.default().requestImage(for: asset, targetSize: size, contentMode: .aspectFill, options: options) { (image, info) in
DispatchQueue.main.async {
cell.imageView.image = image
}
}
编辑: 看起来 fetchKeyAssetsInAssetCollection 并不总是返回正确的结果(最近捕获的图像/视频)。 keyAssets 的定义由apple 模糊定义。更好用
+ (PHFetchResult *)fetchAssetsInAssetCollection:(PHAssetCollection *)assetCollection options:(PHFetchOptions *)options
获取获取结果数组,然后如前所述从获取结果中获取 firstObject。这肯定会返回正确的结果。 :)
【讨论】:
cell.imageView.image = image 需要在主线程中发生。您不能从非主线程修改 UI 元素。
requestImageForAsset 完成块与图像一起返回之前从cellForRowAtIndexPath: 返回的,所以单元格的 imageView 框架为 {0,0,0,0}。这意味着您看不到图像。如果您在完成块中手动设置 imageView 的框架,它不会将标签移开。我目前正在重新加载表格视图之前检索所有缩略图。 PHPhotos 给我留下了深刻的印象 - ALAssets 更容易与 IMO 一起使用。
这是我现在使用的。它处理不同类型的照片集和关键资产丢失的情况。
static func fetchThumbnail(collection: PHCollection, targetSize: CGSize, completion: @escaping (UIImage?) -> ()) {
func fetchAsset(asset: PHAsset, targetSize: CGSize, completion: @escaping (UIImage?) -> ()) {
let options = PHImageRequestOptions()
options.deliveryMode = PHImageRequestOptionsDeliveryMode.highQualityFormat
options.isSynchronous = false
options.isNetworkAccessAllowed = true
// We could use PHCachingImageManager for better performance here
PHImageManager.default().requestImage(for: asset, targetSize: targetSize, contentMode: .default, options: options, resultHandler: { (image, info) in
completion(image)
})
}
func fetchFirstImageThumbnail(collection: PHAssetCollection, targetSize: CGSize, completion: @escaping (UIImage?) -> ()) {
// We could sort by creation date here if we want
let assets = PHAsset.fetchAssets(in: collection, options: PHFetchOptions())
if let asset = assets.firstObject {
fetchAsset(asset: asset, targetSize: targetSize, completion: completion)
} else {
completion(nil)
}
}
if let collection = collection as? PHAssetCollection {
let assets = PHAsset.fetchKeyAssets(in: collection, options: PHFetchOptions())
if let keyAsset = assets?.firstObject {
fetchAsset(asset: keyAsset, targetSize: targetSize) { (image) in
if let image = image {
completion(image)
} else {
fetchFirstImageThumbnail(collection: collection, targetSize: targetSize, completion: completion)
}
}
} else {
fetchFirstImageThumbnail(collection: collection, targetSize: targetSize, completion: completion)
}
} else if let collection = collection as? PHCollectionList {
// For folders we get the first available thumbnail from sub-folders/albums
// possible improvement - make a "tile" thumbnail with 4 images
let inner = PHCollection.fetchCollections(in: collection, options: PHFetchOptions())
inner.enumerateObjects { (innerCollection, idx, stop) in
self.fetchThumbnail(collection: innerCollection, targetSize: targetSize, completion: { (image) in
if image != nil {
completion(image)
stop.pointee = true
} else if idx >= inner.count - 1 {
completion(nil)
}
})
}
} else {
// We shouldn't get here
completion(nil)
}
}
【讨论】:
这是一件很简单的事情……
PHFetchOptions *userAlbumsOptions = [PHFetchOptions new];
userAlbumsOptions.predicate = [NSPredicate predicateWithFormat:@"estimatedAssetCount > 0"];
PHFetchResult *userAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAny options:userAlbumsOptions];
[userAlbums enumerateObjectsUsingBlock:^(PHAssetCollection *collection, NSUInteger idx, BOOL *stop) {
NSLog(@"album title %@", collection.localizedTitle);
PHFetchResult *assetsFetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:nil];
PHAsset *asset = [assetsFetchResult objectAtIndex:0];
NSInteger retinaMultiplier = [UIScreen mainScreen].scale;
CGSize retinaSquare = CGSizeMake(80 * retinaMultiplier, 80 * retinaMultiplier);
[[SDWebImageManager sharedManager] downloadImageWithURL:[NSURL URLWithString:asset.localIdentifier] options:SDWebImageProgressiveDownload targetLocalAssetSize:retinaSquare progress:^(NSInteger receivedSize, NSInteger expectedSize) {
} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (image) {
albumCoverImg.image = image;
}
}];
}];
如果您尚未更新 SDWebImage 分类,则以正常方式加载图像。
【讨论】:
fetchKeyAssets 而不仅仅是获取第一个对象(关键资产不一定只是返回的第一个资产)。