如何在值更改时防止SwiftUI Text抖动并在小数点两侧格式化双精度值?

How to prevent SwiftUI Text from shaking when value changes and format double value both sides of the decimal point?

我有一个倒数计时器。当数字不断变化时,文字水平移动,感觉晃动太多了,因为我每 0.1 秒更新一次计时器。

如何防止文字抖动?这是完整的代码:

struct CountDownTimerView: View {
    
    @ObservedObject var timer = CountdownTimer(seconds: 15)
    
    var body: some View {
        Text(String(format: "%.1f", timer.time))
            .font(Font.system(size: 144).weight(.light))
    }
}

class CountdownTimer: ObservableObject {
    @Published var time: Double
    
    /// time interval in seconds
    let interval = 0.1
    
    lazy var timer = Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { _ in
        self.update()
    }
    
    init(seconds: Double) {
        time = seconds
        timer.fire()
    }
    
    func update() {
        if self.time-interval <= 0 {
            self.time = 0
            timer.invalidate()
        } else {
            self.time -= interval
        }
    }
}

我想将时间显示为双精度值 7.329523 和 07.3。我可以使用 String(format: "%02d", Int(timer.time)) 实现小数点前的格式化,如“07”,或使用 (String(format: "%.1f", timer.time) 的小数点后,如“7.3”。如何格式化小数点两边?

您应该尝试使用每个字符间距相等的字体,通常称为等宽字体。

我找到了两种使用 SwiftUI 实现此目的的方法:

等宽字体

字体的设计更改为等宽。这将影响文本的外观,因为它使用了不同的字体设计。

.font(Font.system(size: 144, design: .monospaced).weight(.light))

自适应字体

另一种更好的方法是将您当前的字体调整为等宽数字。您可以这样做:

.font(Font.monospacedDigit(Font.system(size: 144).weight(.light))())

就是这样(你必须给出前缀为 0 的输出的全宽度,所以 [0 7 . 3] 是四个字符,因此:

let value: CGFloat = 7.329523
Text(String(format: "%04.1f", value))

输出

测试 Xcode 12