如何在给定 15 秒间隔内捕获的坐标数组的情况下绘制和更新形状(SWIFT UI)

Posted

技术标签:

【中文标题】如何在给定 15 秒间隔内捕获的坐标数组的情况下绘制和更新形状(SWIFT UI)【英文标题】:How to draw and update a shape given an array of coordinates captured over a 15 second interval (SWIFT UI) 【发布时间】:2021-12-27 23:26:07 【问题描述】:

(Swift 新手)我有一个在 15 秒内从视频中提取的单个对象的 x 坐标数组。我想遍历这些点,绘制当前点,然后刷新视图并绘制数组中的下一个坐标点,替换前一个。我还使用 swift ui 的 VideoPlayer 在绘图下方同时播放视频。

我有一个形状结构:

struct Stick: Shape 
var points: [CGPoint]
var size: CGSize
func path(in rect: CGRect) -> Path 
    var path = Path()
    path.move(to: points[0])
    for point in points 
        path.addLine(to: point)
    
    return path.applying(CGAffineTransform.identity.scaledBy(x: size.width, y: size.height))
        .applying(CGAffineTransform(scaleX: -1, y: -1).translatedBy(x: -size.width, y: -size.height))



为了遍历每个数组中的点,我创建了一个符合 Observable Object 协议的类。

class Points : ObservableObject
var pointArr = [0.1981825828552246, 0.3635875880718231, 0.363417387008667, 0.36394527554512024, 0.3631347119808197, 0.3628629148006439, 0.36222490668296814]
@Published var point = 0.0

    
    
func updatePoint()
    DispatchQueue.main.async 
        for p in self.pointArr
            self.point = p
            print(self.point)
        
    



然后我有这段代码,我使用按钮单击调用 updatePoint() 并开始遍历坐标数组。

struct VideoView: View 
@ObservedObject var updatePoints :  Points

var body: some View 


ZStack
    Button("Press")
        updatePoints.updatePoint()
    
    //I just used random fixed points for the other coordinates
    Stick(points: [CGPoint(x: updatePoints.point, y: 1.0), CGPoint(x:0.36, y:0.0)], size: CGSize(width: 414, height: 814))
        .stroke(lineWidth: 5.0)
            .fill(Color.green)




我在这段代码背后的思考过程是,因为 Points 类符合 observable object 协议,所以每次在 for 循环中重新分配 point 变量时,都会重新绘制 VideoView,并将新的 point 值传入 Stick 结构。但是,VideoView 仅在 for 循环完成后重绘一次,将数组中的最后一个坐标传递给 Stick 结构。我认为这与主线程中的 for 循环有关,并且在 for 循环完成之前视图不会更新。

这就是我在伪代码中所追求的:

for point in videoPoints
    Stick(point)        //draw that point

这个问题让我困扰了几天,因此非常感谢任何帮助。谢谢!!!

【问题讨论】:

代码无法编译,主要是pointArr。你能创建一个minimal reproducible example吗? @George 我想我修好了,现在试试吧! 我认为问题不在于视频只是在最后一点重绘。我认为它每次都在重新绘制,直到最后一点你才能看到它。因此,您看到的不是一堆Sticks,而是最后一个。在我看来,您可能希望一次将整个数组传递给您的视图,然后使用 ForEach 在正文中对其进行迭代。这将在一个视图中绘制多个Sticks @Yrb 非常感谢您的建议!但是,当我使用 ForEach 循环时,它只会将每个“Sticks”重叠在一起。我想一次只显示一个“棒”。 您想如何确定下一个Stick 的显示时间?我仍然认为它应该在 UI 中处理,而不是在模型中。 【参考方案1】:

您可以使用组合框架随着时间的推移发布这些值。

Points 类中,添加以下内容(替换updatePoint()):

private var cancellables: Set<AnyCancellable> = []

func updatePoint() 
    let timer = Timer.publish(every: 0.2, on: .main, in: .default).autoconnect()

    Publishers.Zip(pointArr.publisher, timer)
        .sink  (p, _) in
            self.point = p
        
        .store(in: &cancellables)

请参阅this 答案,了解延迟值如何与Timer 一起使用。基本上,Zip 仅在 pointArr.publishertimer 都发出一个值时发出一个值。 pointArr 是即时的,所以 timer 可以跟上节奏。

您可以随意设置延迟,目前为0.2 秒。尽管看起来这条线可能会立即到达最后一个点,但这是因为您的采样点在第一个点之后非常靠近。试试像0.5 这样的另一个点,你会看到它仍然在移动之间有延迟。

【讨论】:

效果很好,非常感谢!

以上是关于如何在给定 15 秒间隔内捕获的坐标数组的情况下绘制和更新形状(SWIFT UI)的主要内容,如果未能解决你的问题,请参考以下文章

如何设置 PyQt5 Qtimer 在指定的时间间隔内更新?

Spring Quartz如何动态配置时间(3)

如何使用Android中的Camera2 API在不预览的情况下拍摄多张照片?

NumPy 填充大型数组的给定边界框坐标内的值

python 在给定半径的x,y中心绘制给定数量的等间隔圆周坐标

如何计算给定间隔内的记录?