一个用于录制视图的 Swift 包。可以录制视图并写入视频、gif 或 Live Photo。 还可以从图像数组创建视频、gif 和 Live Photo。
使用 Xcode 内置的 Swift Package Manager 集成。
import FlipBook
该包的主要对象是 FlipBook
对象。 使用它可以录制视图,从图像数组创建资源,并将 Live Photo 保存到用户的照片库。 还有其他特定的编写器对象(FlipBookAssetWriter
、FlipBookLivePhotoWriter
和 FlipBookGIFWriter
),用于更好地控制如何生成资源。 但总的来说,FlipBook
是您用于轻松捕获视图和从图像轻松创建资源的类。
首先创建一个 FlipBook
实例并将 assetType
设置为所需类型。 接下来,通过调用 start
来启动录制,传入您要录制的视图、一个可选的进度闭包(当资产创建进度发生时将被调用)以及一个完成闭包(完成后将返回资产)。 要停止录制,请调用 stop()
,这将触发资产创建开始。 例如
import UIKit
import FlipBook
class ViewController: UIViewController {
// Hold a refrence to `flipBook` otherwise it will go out of scope
let flipBook = FlipBook()
@IBOutlet weak var myAnimatingView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Set the assetType we want to create
flipBook.assetType = .video
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated: animated)
// Start recording when we appear, here we're recording the root view of `ViewController` but could record any arbitary view
flipBook.startRecording(view) { [weak self] result in
// Switch on result
switch result {
case .success(let asset):
// Switch on the asset that's returned
switch asset {
case .video(let url):
// Do something with the video
// We expect a video so do nothing for .livePhoto and .gif
case .livePhoto, .gif:
break
}
case .failure(let error):
// Handle error in recording
print(error)
}
}
// In this example we want to record some animation, so after we start recording we kick off the animation
animateMyAnimatingView {
// The animation is done so stop recording
self.flipBook.stop()
}
}
private func animateMyAnimatingView(_ completion: () -> Void) { ... }
}
您可以查看完整的 iOS 示例 和 macOS 示例。 在 macOS 上,请记住将 wantsLayer
设置为 true
,因为 FlipBook 依赖于渲染 CALayer
以进行快照。
同样,首先创建一个 FlipBook
实例并将 assetType
设置为所需类型。 从图像创建资源时,设置 preferredFramesPerSecond
也很重要,因为它将决定资产的整体持续时间。 为了获得最佳效果,您要包含的所有图像都应具有相同的大小。 最后,调用 makeAsset
,传入您要包含的图像、一个进度闭包和一个完成闭包。 例如
import UIKit
import FlipBook
class ViewController: UIViewController {
// Hold a refrence to `flipBook` otherwise it will go out of scope
let flipBook = FlipBook()
override func viewDidLoad() {
super.viewDidLoad()
// Set `assetType` to the asset type you desire
flipBook.assetType = .video
// Set `preferredFramesPerSecond` to the frame rate of the animation images
flipBook.preferredFramesPerSecond = 24
// Load the images. More realistically these would likely be images the user created or ones that were stored remotely.
let images = (1 ... 48).compactMap { UIImage(named: "animationImage\($0)") }
// Make the asset
flipBook.makeAsset(from: images) { [weak self] (result) in
switch result {
case .success(let asset):
// handle asset
case .failure(let error):
// handle error
}
}
}
}
FlipBook 适用于大多数视图动画和交互,但是许多 CoreAnimation
动画和效果将无法使用上述简单的启动和停止方法。 但是,有一个可选的 animationComposition
闭包,类型为 ((CALayer) -> Void)?
,它允许您使用 AVVideoCompositionCoreAnimationTool
将 CALayer
动画和效果与 FlipBook 视频合成。 例如
import UIKit
import FlipBook
class ViewController: UIViewController {
// Hold a refrence to `flipBook` otherwise it will go out of scope
let flipBook = FlipBook()
@IBOutlet weak var myBackgroundView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Set the assetType we want to create
flipBook.assetType = .video
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated: animated)
// Get the scale of the screen that we capturing on as we'll want to apply the scale when animating for the composition
let scale = view.window?.screen.scale ?? 1.0
// Start recording when we appear, here we're recording a view that will act as the background for our layer animation
flipBook.startRecording(myBackgroundView, compositionAnimation: { layer in
// create a gradient layer
let gradientLayer = CAGradientLayer()
gradientLayer.frame = layer.bounds
gradientLayer.colors = [UIColor.systemRed.cgColor, UIColor.systemBlue.cgColor]
gradientLayer.locations = [0.0, 1.0]
gradientLayer.startPoint = CGPoint.zero
gradientLayer.endPoint = CGPoint(x: 1.0, y: 1.0)
// create a shape layer
let shapeLayer = CAShapeLayer()
shapeLayer.frame = layer.bounds
// remember that layer composition is in pixels not points so scale up
shapeLayer.lineWidth = 10.0 * scale
shapeLayer.lineCap = .round
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor.black.cgColor
shapeLayer.path = UIBezierPath(ovalIn: layer.bounds.insetBy(dx: 150 * scale, dy: 150 * scale)).cgPath
shapeLayer.strokeEnd = 0.0
gradientLayer.mask = shapeLayer
layer.addSublayer(gradientLayer)
let strokeAnimation = CABasicAnimation(keyPath: "strokeEnd")
strokeAnimation.fromValue = 0.0
strokeAnimation.toValue = 1.0
strokeAnimation.duration = 8.0
// must start the animation at `AVCoreAnimationBeginTimeAtZero`
strokeAnimation.beginTime = AVCoreAnimationBeginTimeAtZero
strokeAnimation.isRemovedOnCompletion = false
strokeAnimation.fillMode = .forwards
shapeLayer.add(strokeAnimation, forKey: "strokeAnimation")
}, completion: { [weak self] result in
// Switch on result
switch result {
case .success(let asset):
// Switch on the asset that's returned
switch asset {
case .video(let url):
// Do something with the video
// We expect a video so do nothing for .livePhoto and .gif
case .livePhoto, .gif:
break
}
case .failure(let error):
// Handle error in recording
print(error)
}
})
// After 9 seconds stop recording. We'll have 8 seconds of animation and 1 second of final state
DispatchQueue.main.asyncAfter(deadline: .now() + 9.0) {
self.flipBook.stop()
}
}
}
使用上面的代码生成 gif,您应该得到类似的东西
其中卡片视图是由 FlipBook 录制的背景视图,渐变描边是覆盖在录制之上的图层。 请记住,AVVideoCompositionCoreAnimationTool
的原点位于左下角,而不是像 UIKit
那样位于左上角。
FlipBook 是捕获视图动画和交互或从松散的图像集合组成视频、gif 或 Live Photo 的好方法。 它非常适合只针对屏幕或窗口的一部分。 不仅可以创建视频,还可以创建动画 gif 和 Live Photo。
但是,对于录制长时间的用户会话或在性能达到极限时,它可能不是最佳选择。 对于这些情况,ReplayKit
可能是一个更好的解决方案。 此外,如果系统音频很重要,FlipBook 当前不捕获任何音频,而 ReplayKit
会捕获音频。
注意保护用户的敏感信息和数据非常重要; 不要录制可能包含用户不想录制的信息的屏幕。
CALayer
动画和效果都被捕获(请参阅“高级用法”)。UIView.transition
s 不捕获动画。NSView
的 wantsLayer
设置为 true
View
和 Image
可能会令人困惑。 FlipBook 使用 View
和 Image
在 AppKit 和 UIKit 之间创建类型别名。您可以在这里找到生成的资源库。 您也可以阅读更多关于 FlipBook 的动机。
Brad Gayman
灵感来自
FlipBook 在 MIT 许可下发布。
版权所有 (c) 2020 Brad Gayman
特此授予任何人免费获得本软件及相关文档文件(“软件”)副本的许可,以无限制地处理本软件,包括但不限于使用、复制、修改、合并的权利、发布、分发、再许可和/或销售本软件的副本,并允许向被提供本软件的人员这样做,但须符合以下条件
以上版权声明和本许可声明应包含在本软件的所有副本或重要部分中。
本软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于适销性、适用于特定用途和非侵权性的保证。 在任何情况下,作者或版权所有者均不对任何索赔、损害或其他责任负责,无论是在合同诉讼、侵权行为或其他方面,由本软件或本软件的使用或其他交易引起、产生或与之相关的任何索赔、损害或其他责任。