簡體   English   中英

在 SwiftUI 中使用 didSet 閃爍符號

[英]Blinking symbol with didSet in SwiftUI

這是從一個更大的應用程序合成的。 我試圖通過激活屬性的 didSet 中的計時器來閃爍 SwiftUI 中的 SF 符號。 計時器內的打印語句會打印預期值,但視圖不會更新。

我在我的模型數據中使用結構,我猜這與值與引用類型有關。 我試圖避免從結構轉換為類。

import SwiftUI
import Combine

@main
struct TestBlinkApp: App {
  var body: some Scene {
    WindowGroup {
      ContentView()
    }
  }
}

class Model: ObservableObject {
  @Published var items: [Item] = []
  
  static var loadData: Model {
    let model = Model()
    model.items = [Item("Item1"), Item("Item2"), Item("Item3"), Item("Item4")]
    
    return model
  }
}

struct Item {
  static let ledBlinkTimer: TimeInterval = 0.5
  
  private let ledTimer = Timer.publish(every: ledBlinkTimer, tolerance: ledBlinkTimer * 0.1, on: .main, in: .default).autoconnect()
  
  private var timerSubscription: AnyCancellable? = nil
  
  var name: String
  
  var isLEDon = false
  
  var isLedBlinking = false {
    didSet {
      var result = self
      print("in didSet: isLedBlinking: \(result.isLedBlinking) isLEDon: \(result.isLEDon)")
      guard result.isLedBlinking else {
        result.isLEDon = true
        result.ledTimer.upstream.connect().cancel()
        print("Cancelling timer.")
        return
      }
      result.timerSubscription = result.ledTimer
        .sink {  _ in
          result.isLEDon.toggle()
          print("\(result.name) in ledTimer isLEDon: \(result.isLEDon)")
        }
    }
  }
  
  init(_ name: String) {
    self.name = name
  }
}


struct ContentView: View {
  @StateObject var model = Model.loadData
  
  let color = Color(UIColor.label)
  
  public var body: some View {
    VStack {
      Text(model.items[0].name)
      Image(systemName: model.items[0].isLEDon ? "circle.fill" : "circle")
        .foregroundColor(model.items[0].isLEDon ? .green : color)
      Button("Toggle") {
        model.items[0].isLedBlinking.toggle()
      }
    }
    .foregroundColor(color)
  }
}

觸摸“切換”按鈕會啟動計時器,該計時器會閃爍圓圈。 print 語句顯示值發生變化,但視圖沒有更新。 為什么??

您可以使用動畫來使其閃爍,而不是使用計時器。

Item的模型得到了簡化,你只需要一個布爾變量,像這樣:

struct Item {
    
    var name: String
    
    // Just a toggle: blink/ no blink
    var isLedBlinking = false

    init(_ name: String) {
        self.name = name
    }
}

“艱苦的工作”由視圖完成:更改變量觸發或停止閃爍。 動畫具有魔力:

struct ContentView: View {
    @StateObject var model = Model.loadData
    
    let color = Color(UIColor.label)
    
    public var body: some View {
        VStack {
            Text(model.items[0].name)
                .padding()
            
            // Change based on isLedBlinking
            Image(systemName: model.items[0].isLedBlinking ? "circle.fill" : "circle")
                .font(.largeTitle)
                .foregroundColor(model.items[0].isLedBlinking ? .green : color)
            
                // Animates the view based on isLedBlinking: when is blinking, blinks forever, otherwise does nothing
                .animation(model.items[0].isLedBlinking ? .easeInOut.repeatForever() : .default, value: model.items[0].isLedBlinking)
                .padding()
            
            Button("Toggle: \(model.items[0].isLedBlinking ? "Blinking" : "Still")") {
                model.items[0].isLedBlinking.toggle()
            }
            .padding()
        }
        .foregroundColor(color)
    }
}

使用計時器的另一種方法:

struct ContentView: View {
  @StateObject var model = Model.loadData
  
  let timer = Timer.publish(every: 0.25, tolerance: 0.1, on: .main, in: .common).autoconnect()
  
  let color = Color(UIColor.label)
  
  public var body: some View {
    VStack {
      Text(model.items[0].name)
      
      if model.items[0].isLedBlinking {
        Image(systemName: model.items[0].isLEDon ? "circle.fill" : "circle")
          .onReceive(timer) { _ in
            model.items[0].isLEDon.toggle()
          }
          .foregroundColor(model.items[0].isLEDon ? .green : color)
      } else {
        Image(systemName: model.items[0].isLEDon ? "circle.fill" : "circle")
          .foregroundColor(model.items[0].isLEDon ? .green : color)
      }
      
      Button("Toggle: \(model.items[0].isLedBlinking ? "Blinking" : "Still")") {
        model.items[0].isLedBlinking.toggle()
      }
    }
    .foregroundColor(color)
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM