見出し画像

SwiftUIでTextの中にImageをインラインで表示する

SwiftUIでアイコン画像とテキストを組み合わせて表示するには、HStackやLabelが使われることが多いが、今回は次のようにTextの中にImageをインラインで表示する方法を紹介する。

Inline Image

インラインでImageを表示する

TextにはImageから初期化するイニシャライザがあり、他のTextと連結して画像を表示することができる(公式ドキュメント)。

// Textを結合してインラインでImageを表示
(Text(Image(systemName: "book.fill")) + Text("テキスト"))

// 変数の埋め込みでもOK
Text("\\(Image(systemName: "book.fill"))テキスト")

しかし、Asset Catalogに追加した画像リソースを使用する場合、Textは画像を元のサイズで表示するようで、画像リソースのサイズが大きい場合、テキストサイズと合わなくなってしまう。

Inline Image from Asset Catalog

そこで、一度画像をUIImageとして初期化して、こちらのextensionのようにUIImageをリサイズすれば、テキストサイズに合わせたインライン表示ができる。注意したいのは、UIImage.resize後にUIImage.RenderingMode.alwaysTemplateを指定しないと、foregroundStyleでカラー指定しても画像に反映されない。

struct ContentView: View {
    var body: some View {
        // UIImageとして読み込んで、リサイズ・テンプレートとしてレンダリングすることで、フォントサイズに合うように表示できる
        if let catIcon = catIcon {
            (Text(Image(uiImage: catIcon)) + Text("テキスト"))
                .font(.system(size: 14))
                .foregroundStyle(Color.blue)
                .padding()
        }
    }
    
    private var catIcon: UIImage? {
        UIImage(named: "cat")?
            .resize(size: .init(width: 14, height: 14))?
            .withRenderingMode(.alwaysTemplate)
    }
}

extension UIImage {
    func resize(size _size: CGSize) -> UIImage? {
        let widthRatio = _size.width / size.width
        let heightRatio = _size.height / size.height
        let ratio = widthRatio < heightRatio ? widthRatio : heightRatio

        let resizedSize = CGSize(width: size.width * ratio, height: size.height * ratio)

        UIGraphicsBeginImageContextWithOptions(resizedSize, false, 0.0)
        draw(in: CGRect(origin: .zero, size: resizedSize))
        let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return resizedImage
    }
}
Inline resized Image

参考

この記事が気に入ったらサポートをしてみませんか?