WidgetKit:.timer 文本样式将其扩展以填充宽度,而不是占用空间来适应所包含的字符串

Ale*_*aev 22 ios swift widgetkit swiftui

.timer 文本样式将其扩展以填充宽度,而不是占用空间来容纳所包含的字符串。有办法改变这种行为吗?

\n
Text(entry.timeFinished, style: .timer).multilineTextAlignment(.leading).opacity(0.5).background(Color.red)\n
Run Code Online (Sandbox Code Playgroud)\n

在此输入图像描述

\n
Text("3:41").opacity(0.5).background(Color.blue)\n
Run Code Online (Sandbox Code Playgroud)\n

在此输入图像描述

\n

整个视图:

\n
struct TimePieceWidgetEntryView: View {\n    \n    var entry: Provider.Entry\n    \n    var body: some View {\n        VStack {\n            Text("Timer \xe2\x8f\xb1")\n            Text(Date().addingTimeInterval(600), style: .timer).opacity(0.5)\n        }.font(.title.bold().monospacedDigit())\n        .padding(5)\n        .widgetURL(entry.url)\n    }\n    \n}\n
Run Code Online (Sandbox Code Playgroud)\n

dat*_*inc 3

我对苹果如何构建实时活动和小部件的了解为零。我的猜测是小部件被渲染然后被缓存。这就是为什么标准计时器/发布器之类的东西不会更新 UI。我的猜测是,这些文本计时器填充了空间,以便 Apple 可以在缓存视图的顶部渲染标签,而无需在文本大小发生变化时从小部件中请求新的布局。我这样说是因为我认为容器的填充是一个功能而不是一个错误,所以它可能不会很快改变。

为了解决这个问题,我强制将文本视图的大小设置为应有的最大大小。仍然存在一些问题,但在大多数情况下,这个解决方案看起来不错。

struct TextTimer: View {
    // Return the largest width string for a time interval
    private static func maxStringFor(_ time: TimeInterval) -> String {
        if time < 600 { // 9:99
            return "0:00"
        }
        
        if time < 3600 { // 59:59
            return "00:00"
        }
        
        if time < 36000 { // 9:59:59
            return "0:00:00"
        }
        
        return "00:00:00"// 99:59:59
    }
    init(_ date: Date, font: UIFont, width: CGFloat? = nil) {
        self.date = date
        self.font = font
        if let width {
            self.width = width
        } else {
            let fontAttributes = [NSAttributedString.Key.font: font]
            let time = date.timeIntervalSinceNow
            let maxString = Self.maxStringFor(time)
            self.width = (maxString as NSString).size(withAttributes: fontAttributes).width
        }
    }
    
    let date: Date
    let font: UIFont
    let width: CGFloat
    var body: some View {
        Text(timerInterval: Date.now...date)
            .font(Font(font))
            .frame(width: width > 0 ? width : nil)
            .minimumScaleFactor(0.5)
            .lineLimit(1)
    }
}
Run Code Online (Sandbox Code Playgroud)