Wintersweet是一款快速让控件播映GIF和增加过滤器的框架。
核心其实就是运用CADisplayLink不断刷新和更新GIF帧。
功用
- 支撑全平台系统,macOS、iOS、tvOS、watchOS。
- 支撑增加 Harbeth 滤镜到GIF中播映。
- 支撑播映本地和网络GIF动画。
- 支撑任何控件并运用协议 AsAnimatable 即可快速到达支撑播映GIF功用。
- 支撑六种 ContentMode 内容填充形式。
- 支撑内存缓存 Cached 网络GIF数据。
演示Demo
- Wintersweet 地址
这边现已提供关于macOS和iOS两个端的演示Demo,需求的朋友请移步GitHub下载即可。
简略运用
- 运用本地gif
func setup(imageName: String) {
guard let imagePath = Bundle.main.url(forResource: imageName, withExtension: "gif"),
let data = try? Data(contentsOf: imagePath) else {
return
}
let filters: [C7FilterProtocol] = [
C7SoulOut(soul: 0.75),
C7ColorConvert(with: .rbga),
C7Storyboard(ranks: 2),
]
imageView.play(withGIFData: data, filters: filters, preparation: {
// do something..
})
}
- 运用网络gif
func setupNetworkGif() {
let URL = URL(string: ``URL Link``)!
animatedView.play(withGIFURL: URL, filters: [
C7WhiteBalance(temperature: 5555),
C7LookupTable(image: R.image("lut_x"))
], loop: .count(5), cacheOption: Cached.Options.usedMemoryCache)
}
- 任意控件完结协议
AsAnimatable
均可支撑GIF播映
class GIFView: UIView, AsAnimatable {
}
这边现已对ImageView
完结GIF动态图支撑,so 直接运用即可。✌️
AsAnimatable
- 只需遵从完结过该协议,即可运用播映GIF动画功用,简简略单!
public protocol AsAnimatable: HasAnimatable {
/// 动画循环的总持续时刻
var loopDuration: TimeInterval { get }
/// 当前活动GIF帧图
var activeFrame: C7Image? { get }
/// GIF的总帧数
var frameCount: Int { get }
/// 是否为GIF
var isAnimatingGIF: Bool { get }
/// 核算此GIF的帧巨细
var gifSize: Int { get }
/// 中止动画并从内存中释放GIF数据
func prepareForReuseGIF()
/// 开启GIF动画
func startAnimatingGIF()
/// 中止GIF动画
func stopAnimatingGIF()
}
对外开放两个播映GIF办法:
/// 预备动画并开端播映GIF
/// - Parameters:
/// - withGIFData:GIF图画数据。
/// - filters:Harbeth过滤器适用于GIF帧。
/// - loop:所需的循环数量。默认值为``forever``。
/// - contentMode:用于调整帧巨细的内容形式。默认值为``original``。
/// - bufferCount:要缓冲的帧数。默认值为50。高数字将导致更多的内存运用和更少的CPU负载,反之亦然。
/// - preparation:预备播映时刻回调。
/// - animated:播映GIF完结回调。
public func play(withGIFData data: Data,
filters: [HFilter],
loop: Wintersweet.Loop = .forever,
contentMode: Wintersweet.ContentMode = .original,
bufferCount: Int = 50,
preparation: PreparationCallback? = nil,
animated: AnimatedCallback? = nil) {
...
}
/// 预备动画并开端播映GIF。
/// - Parameters:
/// - withGIFURL:GIF图画网址。
/// - filters:Harbeth过滤器适用于GIF帧。
/// - loop:所需的循环数量。默认值为``forever``。
/// - contentMode:用于调整帧巨细的内容形式。默认值为``original``。
/// - cacheOption:不管天气与否,咱们都应该缓存URL响应。默认值为``disableMemoryCache``。
/// - bufferCount:要缓冲的帧数。默认值为50。高数字将导致更多的内存运用和更少的CPU负载,反之亦然。
/// - preparation:预备播映时刻回调。
/// - animated:播映GIF完结回调。
/// - failed:网络失利回调。
public func play(withGIFURL: URL,
filters: [HFilter],
loop: Wintersweet.Loop = .forever,
contentMode: Wintersweet.ContentMode = .original,
cacheOption: Wintersweet.Cached.Options = .disableMemoryCache,
bufferCount: Int = 50,
preparation: PreparationCallback? = nil,
animated: AnimatedCallback? = nil,
failed: FailedCallback? = nil) {
...
}
ContentMode
- 主要用于图画填充内容更改巨细
public enum ContentMode {
/// 原始图画的尺度。不要用它做任何事情
case original
/// 必要时经过更改内容的宽高比来缩放内容以习惯本身巨细的选项
case scaleToFill
/// 内容缩放以习惯固定方面。其余部分是通明的
case scaleAspectFit
/// 内容缩放以填充固定方面。内容的某些部分或许会被剪切.
case scaleAspectFill
/// 内容缩放以填充固定方面。内容的顶部或左边能够裁剪.
case scaleAspectBottomRight
/// 内容缩放以填充固定方面。内容的底部或右侧部分能够裁剪
case scaleAspectTopLeft
}
- scaleToFill: 拉升图片来习惯控件尺度,图画会变形;
- scaleAspectFit: 坚持图画宽高比例,习惯控件最大尺度;
- scaleAspectFill: 坚持图画宽高比,取图画最小边显现,多余四周部分将被裁减;
- scaleAspectBottomRight: 坚持图画宽高比,取图画最小边显现,多余顶部或左边部分将被裁减;
- scaleAspectTopLeft: 坚持图画宽高比,取图画最小边显现,多余底部或右侧部分将被裁减;
Cached
- 网络数据缓存类型
/// 禁用内存缓存读取
public static let disableMemoryCacheReads = Options(rawValue: 1 << 0)
/// 禁用内存缓存写入
public static let disableMemoryCacheWrites = Options(rawValue: 1 << 1)
/// 读写内存缓存
public static let usedMemoryCache = Options(rawValue: 1 << 2)
/// 禁用内存缓存读取和写入
public static let disableMemoryCache: Options = [.disableMemoryCacheReads, .disableMemoryCacheWrites]
Loop
- GIF循环次数
public enum Loop {
/// 无限循环
case forever
/// 循环播映一次
case never
/// 循环播映指定``count``次
case count(_ count: Int)
}
ImageContainer
- 动画类能够选择恪守的单特点协议,一般具有
image
特点的控件需求完结该协议
public protocol ImageContainer {
/// 用于显现动画帧
var image: C7Image? { get set }
}
extension AsAnimatable where Self: ImageContainer {
/// 根据图画的巨细返回内涵内容巨细
public var intrinsicContentSize: CGSize {
return image?.size ?? CGSize.zero
}
}
AssetType
- 获取数据data类型,统一类型标识符UTI;
public enum AssetType: String, Hashable, Sendable {
/// Unknown format. Either not enough data, or we just don't support this format.
case unknow = "public.unknow"
case jpeg = "public.jpeg"
case png = "public.png"
case gif = "com.compuserve.gif"
case tiff = "public.tiff"
/// Native decoding support only available on the following platforms: macOS 11, iOS 14, watchOS 7, tvOS 14.
case webp = "public.webp"
/// HEIF (High Efficiency Image Format) by Apple.
case heic = "public.heic"
case heif = "public.heif"
/// The M4V file format is a video container format developed by Apple and is very similar to the MP4 format.
/// The primary difference is that M4V files may optionally be protected by DRM copy protection.
case mp4 = "public.mp4"
case m4v = "public.m4v"
case mov = "public.mov"
}
根据给定的数据确认图画的类型
extension AssetType {
/// Determines a type of the image based on the given data.
public init(data: Data?) {
guard let data = data else {
self = .unknow
return
}
self = AssetType.make(data: data)
}
public var isVideo: Bool {
self == .mp4 || self == .m4v || self == .mov
}
}
外部需求运用到的类和协议先简略介绍出来,关于内部运用到的类和协议后续再渐渐介绍!
觉得有协助的铁子,就给我点个星支撑一哈,谢谢铁子们~
GIF动态图框架传送门 Wintersweet 地址。
有什么问题也能够直接联络我,邮箱 yangkj310@gmail.com
最后
- 再附上一个Metal滤镜库HarbethDemo地址,目前包含
100+
种滤镜,同时也支撑CoreImage混合运用。 - 再附上一个开发加速库KJCategoriesDemo地址
- 再附上一个网络基础库RxNetworksDemo地址
- 喜欢的老板们能够点个星,谢谢各位老板!!!
✌️.