🪜
SwiftUIでUIViewRepresentableを使わずCGContextに描く
SwiftUIでCGContextに描く方法はCanvas
CGContextを使ってCoreGraphics系の処理だったりCoreText系の処理だったりをしたいとき、UIViewRepresentableを使ってUIViewをホスティングすることがあります。
UIViewベースで既に作ってあるならそれで良いですが、これから作ったり、いっそSwiftUIだけで作り直したりするならCanvasがいいですね。
CanvasのwithCGContextに渡すクロージャではCGContextが使えます。
var body: some View {
    Canvas { context, size in
        context.withCGContext(content: { cgContext in
	    draw(context: cgContext, size: size)
	})
    }
}
func draw(context: CGContext, size: CGSize) {
    // 描く処理
}
人のコードを勝手にCanvas化
試しに、UIViewRepresentableを使って書かれた以下の記事のコードを勝手にCanvas化してみます。
ContentView.swift
import SwiftUI
import UIKit
struct ContentView: View {
    var body: some View {
        TategakiText(text: """
            こんにちは、
            わたしの名前はふじきです。
            これはswiftuiで実装されています。
            「どうやって実装してるのか」って?
            それはQiitaの記事を読むとわかりますよ!
            記事のリンクですか……
            それは、ヒ・ミ・ツ ♡
            """)
        .padding(40)
    }
}
struct TategakiText: View {
    var text: String
    
    var body: some View {
        Canvas { context, size in
            context.withCGContext(content: { cgContext in
                draw(context: cgContext, size: size)
            })
        }
    }
    
    func draw(context: CGContext, size: CGSize) {
        context.scaleBy(x: 1, y: -1)
        context.translateBy(x: 0, y: -size.height)
        let font = UIFont(name: "HiraMinProN-W6", size: 25)
        let baseAttributes: [NSAttributedString.Key : Any] = [
            .verticalGlyphForm: true,
            NSAttributedString.Key.font: font!]
        let attributedText = NSMutableAttributedString(string: text , attributes: baseAttributes)
        let setter = CTFramesetterCreateWithAttributedString(attributedText)
        let path = CGPath(rect: CGRect(origin:CGPointZero, size: size), transform: nil)
        let frameAttrs = [
            kCTFrameProgressionAttributeName: CTFrameProgression.rightToLeft.rawValue,
        ]
        let ct = CTFramesetterCreateFrame(setter, CFRangeMake(0, 0), path, frameAttrs as CFDictionary)
        
        CTFrameDraw(ct, context)
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
できあがりイメージは以下のようになります。

Discussion