我之前写过一篇文章:
Swift - 使用ALAssetsLibrary获取相簿里所有图片,视频(附样例)。介绍了如何使用
AssetsLibrary 框架来读取并显示系统中的所有照片。
几年以来,相机应用和照片应用发生了显著的变化,增加了许多新特性,包括按时刻来组织照片的方式。但与此同时,
AssetsLibrary
框架却没有跟上步伐。所以到了
iOS 9
后,
AssetsLibrary
框架要被彻底废除。
作为替代,苹果自 iOS 8 起提供了一个更现代化的框架 PhotoKit 。本文将使用 PhotoKit 来实现同之前文章一样的功能:读取并显示设备中的所有照片。
1,Photos框架的特点
淡化了照片库中
URL 的概念,改之使用一个标志符来唯一代表一个资源。同时这个标志符还是动态变化的,也就是说即使同一个资源,每次启动应用后获取的标志符和上一次都是不一样的。
2,获取原图
通过 PHImageManager.defaultManager().requestImageDataForAsset() 这个方法可以获取图片的缩略图或者原图。如果要获取原图,即不对照片大小进行修改或裁剪,那么方法里参数要进行如下设置:
targetSize 设成
PHImageManagerMaximumSize
contentMode 设成
.Default (其实
targetSize 如果是
PHImageManagerMaximumSize 的话,
contentMode 不管设置成什么都会视作
.Default )
(1)与 AssetsLibrary 相比, PhotoKit 没有直接的提供缩略图方法。我们需要指定需要获取的缩略图尺寸,系统会按照你的要求来返回接近该尺寸的图像(会提供刚好大于或等于该尺寸的缩略图,没有的话则返回原图)。
(2)前面提到, PHImageManager.defaultManager().requestImageDataForAsset() 既可以用来获取原图,也可以用来获取缩略图。这里我们使用 PHCachingImageManager,它是 PHImageManager 的子类,所以获取图片的方法是一样的。但这个可以用于缓存 PHAsset,这样可以快速获取照片或视频。在 UICollectionViewController 中使用比较适合。
4,样例说明
(1)启动程序后会获取相机胶卷中所有图片的缩略图,并在
UICollectionViewController 中显示出来。
(2)图片按照创建时间倒序排列(最近拍的照片在最上面)。
(3)点击缩略图,可以查看照片的原图以及图片的相关信息。
(2)图片按照创建时间倒序排列(最近拍的照片在最上面)。
(3)点击缩略图,可以查看照片的原图以及图片的相关信息。
5,效果图如下
--- 首页 CollectionViewController.swift ---
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
import
UIKit
import
Photos
class
CollectionViewController
:
UICollectionViewController
{
///取得的资源结果,用了存放的PHAsset
var
assetsFetchResults:
PHFetchResult
!
///缩略图大小
var
assetGridThumbnailSize:
CGSize
!
/// 带缓存的图片管理对象
var
imageManager:
PHCachingImageManager
!
override
func
viewWillAppear(animated:
Bool
) {
super
.viewWillAppear(animated)
//根据单元格的尺寸计算我们需要的缩略图大小
let
scale =
UIScreen
.mainScreen().scale
let
cellSize = (
self
.collectionViewLayout
as
!
UICollectionViewFlowLayout
).itemSize
assetGridThumbnailSize =
CGSizeMake
( cellSize.width*scale , cellSize.height*scale)
}
override
func
viewDidLoad() {
super
.viewDidLoad()
//则获取所有资源
let
allPhotosOptions =
PHFetchOptions
()
//按照创建时间倒序排列
allPhotosOptions.sortDescriptors = [
NSSortDescriptor
(key:
"creationDate"
,
ascending:
false
)]
//只获取图片
allPhotosOptions.predicate =
NSPredicate
(format:
"mediaType = %d"
,
PHAssetMediaType
.
Image
.rawValue)
assetsFetchResults =
PHAsset
.fetchAssetsWithMediaType(
PHAssetMediaType
.
Image
,
options: allPhotosOptions)
// 初始化和重置缓存
self
.imageManager =
PHCachingImageManager
()
self
.resetCachedAssets()
}
//重置缓存
func
resetCachedAssets(){
self
.imageManager.stopCachingImagesForAllAssets()
}
// CollectionView行数
override
func
collectionView(collectionView:
UICollectionView
,
numberOfItemsInSection section:
Int
) ->
Int
{
return
self
.assetsFetchResults.count
}
// 获取单元格
override
func
collectionView(collectionView:
UICollectionView
,
cellForItemAtIndexPath indexPath:
NSIndexPath
)
->
UICollectionViewCell
{
// storyboard里设计的单元格
let
identify:
String
=
"DesignViewCell"
// 获取设计的单元格,不需要再动态添加界面元素
let
cell = (
self
.collectionView?.dequeueReusableCellWithReuseIdentifier(
identify, forIndexPath: indexPath))!
as
UICollectionViewCell
let
asset =
self
.assetsFetchResults[indexPath.row]
as
!
PHAsset
//获取缩略图
self
.imageManager.requestImageForAsset(asset, targetSize: assetGridThumbnailSize,
contentMode:
PHImageContentMode
.
AspectFill
,
options:
nil
) { (image, nfo)
in
(cell.contentView.viewWithTag(1)
as
!
UIImageView
).image = image
print
(image)
}
return
cell
}
// 单元格点击响应
override
func
collectionView(collectionView:
UICollectionView
,
didSelectItemAtIndexPath indexPath:
NSIndexPath
) {
let
myAsset =
self
.assetsFetchResults[indexPath.row]
as
!
PHAsset
//这里不使用segue跳转(建议用segue跳转)
let
detailViewController =
UIStoryboard
(name:
"Main"
, bundle:
nil
)
.instantiateViewControllerWithIdentifier(
"detail"
)
as
!
ImageDetailViewController
detailViewController.myAsset = myAsset
// navigationController跳转到detailViewController
self
.navigationController!.pushViewController(detailViewController,
animated:
true
)
}
override
func
didReceiveMemoryWarning() {
super
.didReceiveMemoryWarning()
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
import
UIKit
import
Photos
class
ImageDetailViewController
:
UIViewController
{
//选中的图片资源
var
myAsset:
PHAsset
!
//用于显示图片信息
@IBOutlet
weak
var
textView:
UITextView
!
//用于显示原图
@IBOutlet
weak
var
imageView:
UIImageView
!
override
func
viewDidLoad() {
super
.viewDidLoad()
//获取文件名
PHImageManager
.defaultManager().requestImageDataForAsset(myAsset, options:
nil
,
resultHandler: {
_, _, _, info
in
self
.title = (info![
"PHImageFileURLKey"
]
as
!
NSURL
).lastPathComponent
})
//获取图片信息
textView.text =
"日期:\(myAsset.creationDate!)\n"
+
"类型:\(myAsset.mediaType.rawValue)\n"
+
"位置:\(myAsset.location)\n"
+
"时长:\(myAsset.duration)\n"
//获取原图
PHImageManager
.defaultManager().requestImageForAsset(myAsset,
targetSize:
PHImageManagerMaximumSize
, contentMode: .
Default
,
options:
nil
, resultHandler: {
(image, _: [
NSObject
:
AnyObject
]?)
in
self
.imageView.image = image
})
}
override
func
didReceiveMemoryWarning() {
super
.didReceiveMemoryWarning()
}
}
|
7,图像的裁剪与传输策略
上面样例运行后会发现虽然相册中的图片只有7张,但 collectionView 页面却加载了14次:
当然这些策略也是可以通过
requestImageForAsset() 方法中的
options 参数进行设置的(类型是
PHImageRequestOptions。本文样例都是传的都是
nil,即使用默认设置。)
8,PHImageRequestOptions对象常用属性说明
(1)resizeMode 属性
可以设置为 .Exact (返回图像必须和目标大小相匹配), .Fast (比 .Exact 效率更高,但返回图像可能和目标大小不一样,接近且稍大与目标大小) 或者 .None(默认值)。
可以设置为 .Exact (返回图像必须和目标大小相匹配), .Fast (比 .Exact 效率更高,但返回图像可能和目标大小不一样,接近且稍大与目标大小) 或者 .None(默认值)。
(2)deliveryMode 属性
前面提到的在得到高质量的图片之前,会先传输个低质量的策略就是由这个属性设置。一共有三种方式:
.Opportunistic(默认值)
.FastFormat(如果你想要更快的加载速度,且可以牺牲一点图像质量,可以设成这个。)
.HighQualityFormat(如果你只想要高质量的图像,并且可以接受更长的加载时间,那么就设成这个。)
比如我们将 deliveryMode 设置 .HighQualityFormat,那么可以看到图片只加载了7次,之前不会再先获得低质量的图片了。
前面提到的在得到高质量的图片之前,会先传输个低质量的策略就是由这个属性设置。一共有三种方式:
.Opportunistic(默认值)
.FastFormat(如果你想要更快的加载速度,且可以牺牲一点图像质量,可以设成这个。)
.HighQualityFormat(如果你只想要高质量的图像,并且可以接受更长的加载时间,那么就设成这个。)
比如我们将 deliveryMode 设置 .HighQualityFormat,那么可以看到图片只加载了7次,之前不会再先获得低质量的图片了。
默认是 false,表示 requestImageForAsset() 方法是异步操作。如果设置成 true,这个就变成同步的了。
注意:当 synchronous 设为 true 时, deliveryMode 属性就会被忽略,并被当作 .HighQualityFormat 来处理。
9,源码下载: hangge_1233.zip
原文出自: www.hangge.com 转载请保留原文链接: http://www.hangge.com/blog/cache/detail_1233.html