🦋

SwiftUI: GraphicsContextで任意の色のTextやImageをDrawする

2024/04/03に公開

SwiftUIのCanvasImageにはGraphicsContextで動的に描画するものを制御できるAPIがあります。

let size = CGSize(width: 100, height: 100)

var body: some View {
    Canvas { context, size in
        context.draw(Text("Hello World!"), in: CGRect(origin: .zero, size: size))
        context.draw(Image(systemName: "globe"), at: .zero)
    }

    Image(size: size) { context in
        context.draw(Text("Hello World!"), in: CGRect(origin: .zero, size: size))
        context.draw(Image(systemName: "globe"), at: .zero)
    }
}

問題

このGraphicsContextで描画するTextImageの色を指定したい場合にforegroundStyle()を用いると、No exact matches in call to instance method 'draw'というコンパイルエラーになります。これはforegroundStyle()モディファイアがTextImageViewに変換してしまうためです。

Canvas { context, size in
    let text = Text("Hello World!").foregroundStyle(Color.blue)
    context.draw(text, in: CGRect(origin: .zero, size: size)) // compile error

    let image = Image(systemName: "globe").foregroundStyle(Color.blue)
    context.draw(image, at: .zero) // compile error
}

対策

GraphicsContext.resolve()を使い、GraphicsContext.ResolvedTextGraphicsContext.ResolvedImageとしてshadingに色を指定します。

Canvas { context, size in
    var text = context.resolve(Text("Hello World!"))
    text.shading = .color(.blue)
    context.draw(text, in: CGRect(origin: .zero, size: size))

    var image = context.resolve(Image(systemName: "globe"))
    image.shading = .color(.blue)
    context.draw(image, at: .zero)
}

shadingにはcolor以外にもlinearGradientradialGradientなどのグラデーションもあるので、色々試してみると良いかもしれません。

Discussion