I'm making a view to represent certain fractions and I need the parent to adjust its size to the children inside.
I have a Text view and Canvas (drawing the square root symbol) in a ZStack.
When I offset the ZStack to position the square root better, the parent doesn't adjust accordingly. I know that offset on a child moves the view visually but doesn't affect the parent's layout, so whats the appropriate way to do this?
I'd like to figure out how to position the square root, and have the green border encompass all the bounding area, because later on I'm adding a fraction bar, and I want it to be the width of the view.
struct CoordinateView: View {
var body: some View {
VStack(alignment: .leading) {
TermView(value: 3, isSquareRoot: true)
}
.border(.green)
}
}
struct TermView: View {
var value: Int
var isSquareRoot: Bool
var body: some View {
ZStack {
Group {
if isSquareRoot {
SquareRootOverlay()
}
}
Text("\(value)")
.fontDesign(.rounded)
.font(.system(size: 36))
.fontWeight(.bold)
}
}
}
struct SquareRootOverlay: View {
var body: some View {
Canvas { context, size in
let path = Path { path in
path.move(to: CGPoint(x: 4, y: 18))
path.addLine(to: CGPoint(x: 14, y: 38))
path.addLine(to: CGPoint(x: 25, y: 4))
path.addLine(to: CGPoint(x: 57, y: 4))
}
context.stroke(path, with: .color(.black), style: StrokeStyle(lineWidth: 4.4, lineCap: .round, lineJoin: .round))
}
.frame(width: 62, height: 44)
.background(.yellow)
.offset(x: -5, y: -3)
}
}
Try showing SquareRootOverlay
using either .overlay
or .background
. This way, the frame size is determined by the size of the view it is applied to.
Since SquareRootOverlay
currently has a yellow background, you need to use .background
and not .overlay
.
// TermView
var body: some View {
Text("\(value)")
.fontDesign(.rounded)
.font(.system(size: 36))
.fontWeight(.bold)
.background {
if isSquareRoot {
SquareRootOverlay()
}
}
}
Currently, you are setting a fixed-size frame on SquareRootOverlay
. It would probably be a better idea to add padding to the base view (the number), then constrain the square-root sign to the bounds of the view it is being applied to. The Canvas
receives the size of the underlying view, so there is no need for a hard-coded size. Something like:
// TermView
var body: some View {
Text("\(value)")
.fontDesign(.rounded)
.font(.system(size: 36))
.fontWeight(.bold)
.padding(.top, isSquareRoot ? 4 : 0)
.padding(.leading, isSquareRoot ? 30 : 0)
.padding(.trailing, isSquareRoot ? 10 : 0)
.background {
if isSquareRoot {
SquareRootOverlay()
}
}
struct SquareRootOverlay: View {
var body: some View {
Canvas { context, size in
let path = Path { path in
path.move(to: CGPoint(x: 4, y: size.height - 29))
path.addLine(to: CGPoint(x: 14, y: size.height - 9))
path.addLine(to: CGPoint(x: 25, y: 4))
path.addLine(to: CGPoint(x: size.width - 4, y: 4))
}
context.stroke(
path,
with: .color(.black),
style: StrokeStyle(lineWidth: 4.4, lineCap: .round, lineJoin: .round)
)
}
.background(.yellow)
}
}