如何使用可设置动画的矢量进行简单的二维打印



My Swift macOS应用程序每100毫秒渲染一个一维数组(表示音频频谱(的简单2D图。以每秒10帧的速度产生的可视化效果看起来非常不稳定。我想把这个图动画化,这样代码在每个真实数据频谱之间生成5个中间频谱,使帧速率达到60帧/秒。

我的理解是,将一维数组声明为AnimatableVector应该可以实现这一点。但我看过的所有文章(例如,这里和这里(都使用它来制作形状的动画。我的任务只涉及一系列Float,所以它应该更容易。我可以让它渲染连续的情节,但我不能让它为它们设置动画。这里有一个最小可复制性的例子:

第一个是DataSource类,它每半秒生成16个Floats的向量:

class DataSource: ObservableObject {
static let dataSource = DataSource()

@Published var vector: AnimatableVector = AnimatableVector.zero
init() {
vector = generateData()

Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { _ in
self.vector = self.generateData()
}
}
func generateData() -> AnimatableVector {
var points = Array.init(repeating: Float.zero, count: 16)
for i in 0 ..< 16 {
points[i] = Float.random(in: 0.0 ... 1.0)
}
return AnimatableVector(values: points)
}
}

我的ContentView结构简单地调用我的PlotView结构:

struct ContentView: View {
@EnvironmentObject var dataSource: DataSource
var body: some View {
PlotView()
}
}

最后,我的PlotView View进行实际渲染:

struct PlotView: View {
@EnvironmentObject var dataSource: DataSource

var animatableData: AnimatableVector {
get { return dataSource.vector }
set { dataSource.vector = newValue }
}
var body: some View {
Canvas { context, size in
let width: Double  = size.width
let height: Double = size.height
var x: Double = 0.0
var y: Double = 0.0

var path = Path()
path.move(to: CGPoint(x:0.0, y:height-height*Double(animatableData[0]) ) )
for i in 1 ..< 16 {
x = width * Double(i) / Double(15)
y = height - height * Double( animatableData[i] )
path.addLine(to: CGPoint(x: x, y: y))
}
context.stroke( path,
with: .color( Color(red: 1.0, green: 0.0, blue: 0.0) ),
lineWidth: 2.0 )
}
.animation(.easeInOut(duration: 0.2), value: animatableData)
}
}

为了构建和运行这个项目,你需要Majid的AnimatableVector结构(这里(:

该最小可再现示例的完整源代码作为名为"Xcode"的Xcode项目发布;AnimatedVectorTest";在GitHub上(此处(。

情节渲染良好,但动画不起作用。也许我把.animation()修饰符放错了地方,或者我在其中使用了错误的值。这看起来是一种有价值的技术,但我需要在适当的语法方面得到帮助。

我能够让上述项目发挥作用。只需将PlotView视图替换为

struct PlotView: View {
@EnvironmentObject var dataSource: DataSource
public var body: some View {
PlotShape(vector: dataSource.vector)
.stroke(Color.black, lineWidth: 2)
.animation(Animation.linear(duration:0.49),value:dataSource.vector)
}
}

和PlotShape Shape

struct PlotShape: Shape {
var vector: AnimatableVector

public var animatableData: AnimatableVector {
get { vector }
set { vector = newValue }
}

public func path(in rect: CGRect) -> Path {
var x: Double = 0.0
var y: Double = 0.0

var path = Path()
path.move(to:CGPoint(x:0.0, y:rect.height-rect.height*Double(animatableData[0]) ) )
for i in 1 ..< vector.count {
x = rect.width * Double(i) / Double(vector.count - 1)
y = rect.height - rect.height * Double( vector[i] )
path.addLine(to: CGPoint(x: x, y: y))
}
return path
}
}

此示例的完整源代码作为名为"Xcode"的Xcode项目发布;AnimatableVectorDemo";在GitHub上(此处(

正如我在问题中指出的,我正在寻求一种解决方案,将路径和AnimatableVector全部封装在视图中,而不需要单独的Shape,但这可能是不可能的。

最新更新