🦋

SwiftUI: 絵文字を塗りつぶしてシルエットにする

2023/09/24に公開

絵文字を塗りつぶしてシルエットにしたいことよくありますよね!


🛠️の絵文字をシルエット化

それ、NSStringUIGraphicsImageRendererでできます。

struct PlaygroundView: View {
    var body: some View {
        HStack(spacing: 20) {
            Text("🛠️")
                .font(.system(size: 100))
            Image(systemName: "arrowshape.right.fill")
                .font(.largeTitle)
            convertToImage(emoji: "🛠️")
                .renderingMode(.template)
                .foregroundColor(Color.black)
        }
    }

    func convertToImage(emoji: String) -> Image {
        let text = NSString(string: emoji)
        let attributes = [
            NSAttributedString.Key.font: UIFont.systemFont(ofSize: 100)
        ]
        let textSize = text.size(withAttributes: attributes)
        let renderer = UIGraphicsImageRenderer(size: textSize)
        let image = renderer.image { context in
            text.draw(at: .zero, withAttributes: attributes)
        }
        return Image(uiImage: image)
    }
}

ポイント

  • 絵文字を文字列として一度UIImageにする
    • NSString.size(withAttributes:)で画像にした時のサイズを取得
    • UIGraphicsImageRenderer(size:).image(actions:)で文字列を画像としてレンダリング
  • renderingMode(.template)で画像に色をオーバーレイできるようにする

別解

元から塗りつぶしになっている画像を使うパターン。

struct PlaygroundView: View {
    var body: some View {
        HStack(spacing: 20) {
            Text("🛠️")
                .font(.system(size: 100))
            Image(systemName: "arrowshape.right.fill")
                .font(.largeTitle)
            convertToImage(emoji: "🛠️", color: .black)
        }
    }

    func convertToImage(emoji: String, color: Color) -> Image {
        let text = NSString(string: emoji)
        let uiColor = UIColor(color)
        let attributes = [
            NSAttributedString.Key.font: UIFont.systemFont(ofSize: 100)
        ]
        let textSize = text.size(withAttributes: attributes)
        let renderer = UIGraphicsImageRenderer(size: textSize)
        let image = renderer.image { context in
            text.draw(at: .zero, withAttributes: attributes)
            uiColor.setFill()
            context.fill(context.format.bounds, blendMode: .sourceIn)
        }
        return Image(uiImage: image)
    }
}

Discussion