🪜
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