SwiftUI: как рассчитать ширину текстового представления?

У меня неизвестное количество текстовых просмотров, которые мне нужно учитывать (столько часов, сколько проходит во время сна). Каждое текстовое представление длится всего один час, например текст («12»), текст («1») и т. Д.

Мне нужно знать ширину всех объединенных часовых текстовых представлений, чтобы я мог соответственно вычесть из общей геометрии пространство. Ниже приводится функция, которая могла работать с UIKit, но, похоже, не вычисляет правильный размер в SwiftUI. Как я могу этого добиться?

Пример использования:

        Spacer()
    .frame(width: CGFloat(hourAsDate.timeIntervalSince(hoursBetweenSleepStartAndEnd[(hoursBetweenSleepStartAndEnd.firstIndex(of: hourAsDate) ?? 0) - 1]) / totalSleepSeconds)  * calculateSpaceOfHourText())
  Text("\(calendar.component(.hour, from: hourAsDate))")
    .font(Font.system(size: 13.0))
  Spacer()
    .frame(width: CGFloat(sleepEndDate.timeIntervalSince(hourAsDate) / totalSleepSeconds)  * calculateSpaceOfHourText())

Моя вспомогательная функция и расширение:

             //helper
    private func calculateSpaceOfHourText() -> CGFloat {
    
    //The idea here is to try to add up all the space that is taken up by hour Text views and subtract it from the total with of geometry
    
        var hoursToUseForCalculationOfSpace = hoursBetweenSleepStartAndEnd
        
        if hoursBetweenSleepStartAndEnd.first ?? Date() <= sleepStartDate {
            hoursToUseForCalculationOfSpace.removeFirst()
        }
        
        if hoursBetweenSleepStartAndEnd.last ?? Date() >= sleepEndDate {
            hoursToUseForCalculationOfSpace.removeLast()
        }
        return (proxy.size.width - hoursToUseForCalculationOfSpace.map { calendar.component(.hour, from: $0) }.map { "\($0)".widthOfString(usingFont: UIFont.systemFont(ofSize: 13, weight: .regular)) }.reduce(0, +))
    }
}

extension String {
   func widthOfString(usingFont font: UIFont) -> CGFloat {
        let fontAttributes = [NSAttributedString.Key.font: font]
        let size = self.size(withAttributes: fontAttributes)
        //print("THIS width = \(size.width)")
        return size.width
    }
}

1 ответ

Не дает прямого ответа на вашу проблему, но, возможно, направление, в которое нужно обратить внимание, - это PreferenceKey протокол в сочетании с GeometryReader. Например, следующий код рисует RoundedRectangle в фоновом режиме с высотой изменяемого вида:

      struct HeightPreferenceKey: PreferenceKey {
    static var defaultValue: [CGFloat] = []
    
    static func reduce(value: inout [CGFloat], nextValue: () -> [CGFloat]) {
        value.append(contentsOf: nextValue())
        
    }
    
    typealias Value = [CGFloat]
}

struct HeightPreferenceViewSetter: View {
    var body: some View {
        GeometryReader { geometry in
            RoundedRectangle(cornerRadius: 13)
                .fill(Color.gray)
                .preference(key: HeightPreferenceKey.self,
                            value: [geometry.size.height]) 
              }
    }
}
struct HeightModifier: ViewModifier {
    func body(content: Content) -> some View {
        content
            .background(HeightPreferenceViewSetter())
            
    }
}
Другие вопросы по тегам