I\'d like to create a text view inside a circle view. The font size should be automatically set to fit the size of the circle. How can this be done in SwiftUI? I tried scaledToF
Here's a solution that hides the text resizing code in a custom modifier which can be applied to any View, not just a Circle, and takes a parameter specifying the fraction of the View that the text should occupy.
(I have to agree that while @szemian's solution is still not ideal, her method seems to be the best we can do with the current SwiftUI implementation because of issues inherent in the others. @simibac's answer requires fiddling to find a new magic number to replace 0.4 any time the text or its attributes--font, weight, etc.--are changed, and @giuseppe-sapienza's doesn't allow the size of the circle to be specified, only the font size of the text.)
struct FitToWidth: ViewModifier {
var fraction: CGFloat = 1.0
func body(content: Content) -> some View {
GeometryReader { g in
content
.font(.system(size: 1000))
.minimumScaleFactor(0.005)
.lineLimit(1)
.frame(width: g.size.width*self.fraction)
}
}
}
Using the modifier, the code becomes just this:
var body: some View {
Circle().strokeBorder(Color.red, lineWidth: 30)
.aspectRatio(contentMode: .fit)
.overlay(Text("Text")
.modifier(FitToWidth(fraction: fraction)))
}
Also, when a future version of Xcode offers SwiftUI improvements that obviate the .minimumScaleFactor
hack, you can just update the modifier code to use it. :)
If you want to see how the fraction parameter works, here's code to let you adjust it interactively with a slider:
struct ContentView: View {
@State var fraction: CGFloat = 0.5
var body: some View {
VStack {
Spacer()
Circle().strokeBorder(Color.red, lineWidth: 30)
.aspectRatio(contentMode: .fit)
.overlay(Text("Text")
.modifier(FitToWidth(fraction: fraction)))
Slider(value: $fraction, in:0.1...0.9, step: 0.1).padding()
Text("Fraction: \(fraction, specifier: "%.1f")")
Spacer()
}
}
}
and here's what it looks like: