swiftuicanvastextcgrect

How to fill rect beneath Text inside Canvas in SwiftUI


I'm trying to draw text with a filled and inset rectangle under the text that matches the text's size inside a Canvas in SwiftUI, but I'm unable to figure out how to get the dimensions of the Text view.

struct ContentView: View {
    var body : some View {
        Canvas { context,size in
            let TEXT = Text("Some text").foregroundColor(.black)
//            context.fill(TEXT.boundingRect.insetBy(dx: -4, dy: -2), with: .color(.red)) // error: no boundingRect
            context.draw(TEXT, at: CGPoint(x: size.width/2,y: size.height/2))
        }
    }
}

Solution

  • You need ask the GraphicsContext to ‘resolve’ the Text. You can then ask the ResolvedText to measure itself.

    struct ContentView: View {
      var body: some View {
        Canvas { gc, size in
          let text: Text = Text("some text")
            .foregroundColor(.black)
          let resolvedText = gc.resolve(text)
    
          let textSize = resolvedText.measure(in: size)
          let textRect = CGRect(
            x: 0.5 * (size.width - textSize.width),
            y: 0.5 * (size.height - textSize.height),
            width: textSize.width,
            height: textSize.height
          )
    
          let bgRect = textRect.insetBy(dx: -5, dy: -5)
          gc.fill(Path(bgRect), with: .color(.mint))
    
          gc.draw(resolvedText, in: textRect)
        }
      }
    }
    

    Output:

    black text on a mint rectangle

    I found that I needed to make the type of the text variable explicit (let text: Text). Otherwise, the compiler infers type some View, which can't be resolved.