[ SwiftUI ]TextのModifierを使って特定のフォントリソースを簡単に利用できるようにする。その１

今回は、仕事を通して勉強したことを忘れないように自分なりにまとめていきます。

TextのModifierを使って、UIKitでフォントのカスタマイズや特定のフォントリソースを簡単に利用できるようにし、かつ行間の調整も動的に行えるようにしてSwiftUIでのTextをプロジェクト内でフォントを一元的かつ柔軟に管理するために設計していこうと思います。

## ・今回のテーマ
コードは書くよりも読む時間の方が長いので、可読性を高める必要がある
コードの可読性を高めたり再利用されることが多い箇所などを見やすくするため

・コーディングの原則
[Simplicity / 単純]
[Conciseness / 簡潔] 
[Clarity / 明確] 

## ・フォントファイルをプロジェクトに紐付ける
様々なフォントを使用することを想定したいので、プロジェクト内にFontというフォルダーを作りそこに今回使うフォントファイルをドラックアンドドロップして準備していきます。(とりあえず一つだけ設定できるよう準備していきます)

![スクリーンショット 2024-12-10 13.23.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3808574/1dbd845b-5017-28f4-bccb-d2907edf9a5c.png)
<font color="yellow">＊ファイルをドラックアンドドロップした際にAddtotargetsにチェックをつけることも忘れずに！</font>

## ・次にinfo.plistでフォントの設定を行う
「info.plist」に Fonts provided by application を追加

![スクリーンショット 2024-12-10 13.31.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3808574/d9573b72-2f93-a813-0b6b-39a39cf063de.png)
そこに追加したいフォントのファイル名を設定する

これでプロジェクトで「DotGothic16-Regular.ttf」を使う準備ができました。

## ・Modifierを用意する

列挙型でカスタムフォントの名前を管理
```swift
// 列挙型: カスタムフォントの名前を管理
enum CustomFontName {
    case DotGothic16
    // フォント名を返す関数
    func fontName() -> String {
        switch self {
        case .DotGothic16:
            return "DotGothic16-Regular" // フォント名を取得
            
        }
    }
}
```
カスタムフォントをUIFontとして取得するための関数を書く
```swift
extension UIFont {
    // カスタムフォントをUIFontとして取得するための関数
    static func customFont(name: CustomFontName, size: CGFloat) -> UIFont {
        let fontName = name.fontName() // フォント名を取得
        // 指定されたフォント名とサイズでUIFontを生成。見つからない場合はシステムフォントを返す
        return UIFont(name: fontName, size: size) ?? .systemFont(ofSize: size)
    }
}
```
カスタムフォントをSwiftUIのFontとして取得するための関数を書く
```swift
extension Font {
    // カスタムフォントをSwiftUIのFontとして取得するための関数
    static func customFont(name: CustomFontName, size: CGFloat) -> Font {
        let fontName = name.fontName() // フォント名を取得
        // UIFontを生成し、SwiftUIのFontに変換して返す
        if let uiFont = UIFont(name: fontName, size: size) {
            return Font(uiFont)
        }
        // 指定のフォントが見つからない場合はシステムフォントを返す
        return .system(size: size)
    }
}
```
ViewModifierでカスタムフォントの運用とフォントのサイズ変更における行間の調整のためのコード
```swift
// SwiftUI ViewModifier: カスタムフォントと行間を運用
struct CustomFontWithLineHeight: ViewModifier {
    let name: CustomFontName // カスタムフォントの名前
    let size: CGFloat        // フォントサイズ
    let lineHeight: CGFloat  // 行間の高さ
    // コンテンツにフォントと行間を運用する
    func body(content: Content) -> some View {
        let uiFont = UIFont.customFont(name: name, size: size) // UIFontを取得
        content
            .font(Font(uiFont)) // カスタムフォントを運用
            .lineSpacing(lineHeight - uiFont.lineHeight) // 指定された行間を運用
            .padding(.vertical, (lineHeight - uiFont.lineHeight) / 2) // 行間の高さに合わせて上下のパディングを設定
    }
}
```
最後に、Viewにカスタムフォントと行間を運用するための拡張関数を書く
```swift
extension View {
    // Viewにカスタムフォントと行間を運用するための拡張関数
    func customFontWithLineHeight(name: CustomFontName, size: CGFloat, lineHeight: CGFloat) -> some View {
        // カスタムViewModifierを運用
        self.modifier(CustomFontWithLineHeight(name: name, size: size, lineHeight: lineHeight))
    }
}
```
## ・コード全体
TextStyle.swift
```swift
import SwiftUI
// 列挙型: カスタムフォントの名前を管理
enum CustomFontName {
    case DotGothic16
    // フォント名を返す関数
    func fontName() -> String {
        switch self {
        case .DotGothic16:
            return "DotGothic16-Regular" // フォント名を取得
            
        }
    }
}

extension UIFont {
    // カスタムフォントをUIFontとして取得するための関数
    static func customFont(name: CustomFontName, size: CGFloat) -> UIFont {
        let fontName = name.fontName() // フォント名を取得
        // 指定されたフォント名とサイズでUIFontを生成。見つからない場合はシステムフォントを返す
        return UIFont(name: fontName, size: size) ?? .systemFont(ofSize: size)
    }
}

extension Font {
    // カスタムフォントをSwiftUIのFontとして取得するための関数
    static func customFont(name: CustomFontName, size: CGFloat) -> Font {
        let fontName = name.fontName() // フォント名を取得
        // UIFontを生成し、SwiftUIのFontに変換して返す
        if let uiFont = UIFont(name: fontName, size: size) {
            return Font(uiFont)
        }
        // 指定のフォントが見つからない場合はシステムフォントを返す
        return .system(size: size)
    }
}
// SwiftUI ViewModifier: カスタムフォントと行間を運用
struct CustomFontWithLineHeight: ViewModifier {
    let name: CustomFontName // カスタムフォントの名前
    let size: CGFloat        // フォントサイズ
    let lineHeight: CGFloat  // 行間の高さ
    // コンテンツにフォントと行間を運用する
    func body(content: Content) -> some View {
        let uiFont = UIFont.customFont(name: name, size: size) // UIFontを取得
        content
            .font(Font(uiFont)) // カスタムフォントを運用
            .lineSpacing(lineHeight - uiFont.lineHeight) // 指定された行間を運用
            .padding(.vertical, (lineHeight - uiFont.lineHeight) / 2) // 行間の高さに合わせて上下のパディングを設定
    }
}

extension View {
    // Viewにカスタムフォントと行間を運用するための拡張関数
    func customFontWithLineHeight(name: CustomFontName, size: CGFloat, lineHeight: CGFloat) -> some View {
        // カスタムViewModifierを運用
        self.modifier(CustomFontWithLineHeight(name: name, size: size, lineHeight: lineHeight))
    }
}

```
## ・TextにModifierとして使ってフォント・サイズ指定する
```swift
Text("Hello World")
 .customFontWithLineHeight(name: .DotGothic16, size: 30, lineHeight: 10)
```
これで実装できました！

## ・おわりに
今回は自分なりに勉強したことをまとめてみました。
少しでも同じ勉強中の初心者の方のお役に立てればと思います。

実際に書いてみると、とてもわかりやすく便利なものと気付かされたのでもう少し自分なりに深掘りしていこうと思います。


## ・続き記事

https://qiita.com/Apple81999/items/e113299718c6e71adb7b