I have unknown number of Text views I need to account for (as many hours that pass during sleep). Each Text view is just a single hour e.g. Text("12"), Text("1") etc.
I need to know the width of all the combined hour Text Views so I can subtract from the overall geometry to space accordingly. The below is a widthOfString
function that may have worked with UIKit but doesn't seem to calculate the proper size in SwiftUI. How can I achieve this?
Example usage:
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())
My Helper Function and Extension:
//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
}
}
Not direct an answer to your problem, but maybe a direction to look into is the
PreferenceKey
protocol in combination withGeometryReader
. For example the following code draws aRoundedRectangle
in the background with the height of the view it modifies: