LBJMediaBrowser 是一个在 SwiftUI 框架下实现的图片视频浏览器。
- 支持的图片类型:
UIImage
、PHAsset
、URL
和 Gif 动态图。 - 支持的视频类型:
PHAsset
和URL
。 - 网格模式浏览。
- 分页模式浏览。
- 可自定义不同加载阶段显示的内容。
使用 Swift Package Manager 安装:
- 复制库的路径。
https://github.com/Lebron1992/LBJMediaBrowser
- 在 Xcode 中打开菜单
File / Add Packages
。 - 把路径粘贴到搜索框,根据提示把库添加到项目中。
LBJMediaBrowser 为每一种图片和视频都定义了对应的类型。它们都是继承自 Media
的 class
类型,方便用于自定义自己的类型。
图片
MediaUIImage
:UIImage
类型的图片。MediaURLImage
:URL
类型的图片。MediaPHAssetImage
:PHAsset
类型的图片。MediaGifImage
:Gif 动态图,支持从Bundle
和Data
中获取动态图数据。MediaURLImage
和MediaPHAssetImage
会自动识别对应类型的动态图。
视频
MediaURLVideo
:URL
类型的视频。MediaPHAssetVideo
:PHAsset
类型的视频。
直接调用对应的初始化函数即可创建对象:
// MediaUIImage
let uiImage = UIImage(named: "image_name")
let mediaUIImage = MediaUIImage(uiImage: $uiImage)
// MediaURLImage
let imageUrl = URL(string: "https://www.example.com/test.png")!
let urlImage = MediaURLImage(imageUrl: imageUrl)
// MediaPHAssetImage
let phAsset = ... // 从 Photo Library 中获取
let assetImage = MediaPHAssetImage(asset: phAsset)
// Gif Image
let gifImage1 = MediaGifImage(source: .bundle(name: "lebron", bundle: .main)
let gifImage2 = MediaGifImage(source: .data(gifData))
let gifUrl = URL(string: "https://www.example.com/test.gif")!
let gifImage3 = MediaURLImage(imageUrl: gifUrl)
// MediaURLVideo
let videoUrl = URL(string: "https://www.example.com/test.mp4")!
let urlVideo = MediaURLVideo(videoUrl: videoUrl, previewImageUrl: nil)
// MediaPHAssetVideo
let phAsset = ... // 从 Photo Library 中获取
let assetVideo = MediaPHAssetVideo(asset: phAsset)
还可以通过继承对应的类型,来定义自己的媒体类型,例如:
import LBJMediaBrowser
final class MyMediaUIImage: MediaUIImage {
let caption: String
init(uiImage: UIImage, caption: String) {
self.caption = caption
super.init(uiImage: uiImage)
}
}
LBJMediaBrowser 定义了 LBJGridMediaBrowser
类型,用于以网格模式浏览媒体。例如:
let medias = [uiImage, urlImage, assetImage, urlVideo, assetVideo]
let dataSource = LBJGridMediaBrowserDataSource(medias: medias)
LBJGridMediaBrowser(dataSource: dataSource)
自定义显示内容
LBJGridMediaBrowserDataSource
提供了丰富的自定义显示内容的闭包:
public init(
sections: [GridSection],
placeholderProvider: ((Media) -> AnyView)? = nil,
progressProvider: ((Float) -> AnyView)? = nil,
failureProvider: ((Error) -> AnyView)? = nil,
contentProvider: ((MediaLoadedResult) -> AnyView)? = nil,
sectionHeaderProvider: ((GridSection) -> AnyView)? = nil,
pagingMediaBrowserProvider: (([Media], Int) -> LBJPagingMediaBrowser)? = nil
) { }
placeholderProvider
: 媒体未加载时显示的内容,闭包的参数是Media
类型,可以根据这个参数为图片和视频分别定义显示内容。progressProvider
: 媒体正在加载时显示的内容,闭包的参数是Float
类型,表示下载进度。此闭包只对图片有效。failureProvider
: 媒体加载失败时显示的内容,闭包的参数是Error
类型,contentProvider
: 媒体加载成功时显示的内容,闭包的参数是MediaLoadedResult
类型,可以根据这个参数为图片和视频分别定义显示内容。sectionHeaderProvider
: section header 显示的内容,闭包的参数是GridSection
类型,可以根据这个参数为为不同的 section 定义 header 显示内容。pagingMediaBrowserProvider
: 点击跳转的分页浏览器。参数[Media]
是浏览器中的所有媒体组成的数组, 参数Int
是用户点击的媒体在数组中的索引。
例如:
let uiImageSection = TitledGridSection(title: "UIImages", medias: uiImages)
let urlImageSection = TitledGridSection(title: "URLImages", medias: urlImages)
let dataSource = LBJGridMediaBrowserDataSource(
sections: [uiImageSection, urlImageSection],
placeholderProvider: {
MyPlaceholderView(media: $0)
.asAnyView()
},
progressProvider: {
MyProgressView(progress: $0)
.foregroundColor(.white)
.frame(width: 40, height: 40)
.asAnyView()
},
failureProvider: {
MyErrorView(error: $0)
.font(.system(size: 10))
.asAnyView()
},
contentProvider: {
MyGridContentView(result: $0)
.asAnyView()
},
sectionHeaderProvider: {
Text($0.title)
.asAnyView()
},
pagingMediaBrowserProvider: { medias, page in
let dataSource = LBJPagingMediaBrowserDataSource(
medias: medias,
placeholderProvider: {
MyPlaceholderView(media: $0)
.asAnyView()
},
progressProvider: {
MyProgressView(progress: $0)
.foregroundColor(.white)
.frame(width: 100, height: 100)
.asAnyView()
},
failureProvider: { error, retry in
MyErrorView(error: error, retry: retry)
.font(.system(size: 16))
.asAnyView()
},
contentProvider: {
MyPagingContentView(result: $0)
.asAnyView()
})
let browser = LBJPagingBrowser(dataSource: dataSource, currentPage: page)
browser.autoPlayVideo = true
return LBJPagingMediaBrowser(browser: browser)
}
)
设置媒体的大小
通过调用 minItemSize
方法设置媒体的大小,默认是 (80, 80)
。
LBJGridMediaBrowser(dataSource: dataSource)
.minItemSize(.init(width: 100, height: 200))
设置媒体之间的间隔
通过调用 itemSpacing
方法设置媒体之间的间隔,默认是 2
。
LBJGridMediaBrowser(dataSource: dataSource)
.itemSpacing(4)
设置点击媒体时是否跳转到分页模式浏览
通过调用 itemSpacing
方法设置点击媒体时是否跳转到分页模式浏览,默认是 true
。
NavigationView {
LBJGridMediaBrowser(dataSource: dataSource)
.browseInPagingOnTapItem(true)
}
LBJMediaBrowser 定义了 LBJPagingMediaBrowser
类型,用于以分页模式浏览媒体。例如:
let browser = LBJPagingBrowser(medias: medias)
LBJPagingMediaBrowser(browser: browser)
自定义显示内容
LBJPagingMediaBrowserDataSource
提供了丰富的自定义显示内容的闭包:
public init(
medias: [Media],
placeholderProvider: ((Media) -> AnyView)? = nil,
progressProvider: ((Float) -> AnyView)? = nil,
failureProvider: ((_ error: Error, _ retry: @escaping () -> Void) -> AnyView)? = nil,
contentProvider: ((MediaLoadedResult) -> AnyView)? = nil
) { }
其中的泛型类型分别代表媒体的四个加载阶段的显示内容:
placeholderProvider
: 媒体未加载时显示的内容,闭包的参数是Media
类型,可以根据这个参数为图片和视频分别定义显示内容。progressProvider
: 媒体正在加载时显示的内容,闭包的参数是Float
类型,表示下载进度。此闭包只对图片有效。failureProvider
: 媒体加载失败时显示的内容,闭包的第一个参数是Error
类型,第二参数是retry
闭包,可以调用retry()
重新加载媒体。contentProvider
: 媒体加载成功时显示的内容,闭包的参数是MediaLoadedResult
类型,可以根据这个参数为图片和视频分别定义显示内容。
设置当前页数
当 LBJPagingMediaBrowser
显示时,默认显示第一页。在初始化 LBJPagingBrowser
时,可以指定当前页数:
let browser = LBJPagingBrowser(medias: medias, currentPage: 10)
还可以通过调用 setCurrentPage
方法来手动改变当前页数:
browser.setCurrentPage(10, animated: false)
animated
默认是 true
。
设置是否自动播放视频
通过设置 LBJPagingBrowser
的属性 autoPlayVideo
来设置是否自动播放视频, 默认是 false
。
let browser: LBJPagingBrowser = {
let browser = LBJPagingBrowser(medias: medias)
browser.autoPlayVideo = true
return browser
}()
设置点击媒体时执行的操作
通过调用 onTapMedia
方法设置点击媒体时执行的操作。
LBJPagingMediaBrowser(browser: browser)
.onTapMedia { media in
// ...
}
为了给用户再次浏览媒体时提供更好的体验,默认情况下,LBJMediaBrowser 会把图片保存在磁盘中,并且默认过期时间为 7
天,没有缓存的大小限制。另外在使用中也会把图片缓存到内存,默认最大使用内存为 100MB
;当超过 100MB
时,会自动根据缓存的时间自动清理最旧的图片,使内存占用减少到 80MB
以下。
在显示图片时,首先从内存缓存中查找图片;如果没找到,则继续从磁盘中查找;如果还是没找到,才会真正去加载图片。
如果需要自定义缓存的规则,可以通过 EnvironmentValues
来设置。代码如下:
let imageCache: ImageCache? = {
let diskStorage = try? ImageDiskStorage(config: .init(
name: "ImageCache",
sizeLimit: 0,
expiration: .days(7)
))
let memoryStorage = ImageMemoryStorage(
memoryCapacity: 100_000_000,
preferredMemoryCapacityAfterPurge: 80_000_000
)
let cache = ImageCache(diskStorage: diskStorage, memoryStorage: memoryStorage)
return cache
}()
let mediaBrowserEnvironment = LBJMediaBrowserEnvironment(imageCache: imageCache)
LBJGridMediaBrowser(dataSource: dataSource)
.environment(\.mediaBrowserEnvironment, mediaBrowserEnvironment)
如果不需要缓存到磁盘,把 diskStorage
设置为 nil
:
let cache = ImageCache(diskStorage: nil, memoryStorage: memoryStorage)
使用 AlamofireImage 下载网络图片。
使用 LBJImagePreviewer 展示图片。
请使用 GitHub issues。