【SwiftUI】アプリ制作で使える全フォントを一覧で表示するアプリを作る方法

13 min

こんにちは、たいちです(@taichi_swift_)

たかし

たかし

アプリ制作で使えるフォントの一覧の情報が見当たらない!自由なフォントを使う方法がわからなくて困ってます…

こちらお悩みを解決します。

本記事の内容
  • iPhone・iPadにインストールされてる全フォントを一覧で表示するアプリを作る方法

 

本記事の読者
  • アプリのデザインをレベルアップさせたい人
  • フォントについて勉強したい人

 

本記事を読むメリット

iPhone・iPadにインストールされてる全フォントを一覧で表示するアプリを作る方法がわかる。
標準フォント以外を使う方法がわかり、今後のデザインに生かすことができる。

みなさんは、アプリのデザインを考える時に文字のフォントを変えたくなる時はありませんか?

SwiftUIでは、”AvenirNext-UltraLightItalic”のように自分で文字を書いて指定するため、一文字でも打ち間違えると正しいフォントで表示されません。

しかも、使えるフォントの一覧をまとめた情報がないので、仕方なく標準フォントを使っている方も少なからずいるのではないでしょうか。

そこでSwiftUIでフォント一覧を表示する方法を解説します。アプリ制作初心者の方でも理解できるように解説もつけているので、実際にアプリを作りながら記事を読んでみてくださいね。

この記事を読んだら、フォントを自由自在に操れるようになるよ!

たいち

たいち

ソースコードはこちらに載せています。

フォントを取得するアプリの完成形

まずは、作るアプリのイメージを固めましょう。今回作るアプリの完成形をみてください

アプリを僕のiPhoneXRに入れたので、iPhoneXRにインストールされているフォントが表示されます。
自分のデバイスにフォントをインストールする方法はまた後日紹介しますね。

フォントを取得するアプリの作り方

【環境】

  • Xcode 11.4
  • Swift5.2

iPhoneアプリとして作っていきます。

macOSやwatchOS、tvOSでも工夫すれば作れそうだね!

たいち

たいち

Xcodeでプロジェクトを作る

まずはXcodeで新しいプロジェクトを作ります。

  1. STEP

    「iOS」の「Single View App」を選び、Nextをクリックします。

    iOS を選び、 Single View Appを選びます。
  2. STEP

    Product Nameを「Get Fonts」として、Swift・SwiftUIを選択します。

    ProductNameを GetFontsにします。

     

こちらの記事で、プロジェクトの作り方について書いています。

フォントの一覧を表示する

ContentView.swiftに、フォントファミリーを入れる定数を宣言します。

//struct ContentView: View {
//この間に書く!  
  let familyNames = UIFont.familyNames
//var body: some View {

UIFont.familyNamesで、デバイスにインストールされているフォントファミリーを[String]型で取得します

フォントファミリーっていうのはベースとなるフォントと太さ、細さや傾きなどのバリエーション全てを含めたグループのことだよ。

たいち

たいち

[String]のデータ型についてはこちらの記事で取り扱ってます。

letは定数を定義するキーワードだよ!

この記事で解説してます!

たいち

たいち

次は、一つ一つのフォントファミリーからの太さやバリエーション全てを取り出して、一つ一つのフォントを取得するための関数(メソッド)を書いていきます。

let familyNames = UIFont.familyNames
var body: some View {
//次の説明で書くよ!
}

//var body... のカッコ外に、funcを書くよ
func getFontNames() -> [String] {
    var fontNames: [String] = []
    for familyName in self.familyNames {
        for fontName in UIFont.fontNames(forFamilyName: familyName) {
            fontNames.append(fontName)
        }
    }
    return fontNames
}

フォントファミリーごとに、UIFont.fontNames(foFamilyName: )を使って全てのフォントを取り出しています。

 

準備ができたので、ビューの中身を書いていきます。

var body: some View {
    let board = UIPasteboard.general
    return NavigationView {
        List {
            Text("Fonts Count: \(self.getFontNames().count)")
            ForEach(self.getFontNames(), id: \.self) { fontName in
                NavigationLink(destination: FontDetailView(fontName: fontName)) {
                    Text("ABCDEFG:" + fontName)
                        .font(Font.custom(fontName, size: 18))
                        .foregroundColor(.primary)
                }
            }
        }
        .navigationBarTitle( Text("All Fonts") )
    }
    .onAppear {
        board.prepareForInterfaceBuilder()
    }
}

 

フォントを表示するビューについての解説

{}の外側から説明します。

NavigationView {}

こちらの記事で解説しています。
画面遷移に必要になります。

List {}

いろんなアプリで使われている「リスト」を表示します。

詳しくはまた後日記事にします。

Text()

文字を表示します。

Text("Fonts Count: \(self.getFontNames().count)")

とすることで、フォントの数を表示することができます。

\()のカッコ内に変数を入れると、文字列として扱えるよ!

たいち

たいち

ForEach(self.getFontNames(), id: \.self) { fontName in
    //...省略
}

getFontNames()の戻り値の要素の数だけ {}の中身を繰り返します。(ループする)

fontName にはn回目のループのたびに配列のn番目の要素が代入されます。

ForEachはSwiftUIのチュートリアルでも使われてるから、詳しくはそっちもみてみてね

たいち

たいち

NavigationLink(destination: FontDetailView(fontName: fontName)) {
    Text("ABCDEFG:" + fontName)
        .font(Font.custom(fontName, size: 18))
        .foregroundColor(.primary)
}

NavigatinLinkがNavigationViewの{}のカッコ内に入っていれば、タップで画面遷移ができます。
これもこちらの記事で紹介しています。

//ABCDEFGとフォントの名前を、そのフォントで表示します。
Text("ABCDEFG:" + fontName)
    .font(Font.custom(fontName, size: 18))
    .foregroundColor(.primary)
//.foregroundColor(.primary)とすることで、ダークモードにも対応できます。

ここまで書けたら一度アプリを実行してみましょう。

NavigationLink(destination: FontDetailView(fontName: fontName)) {
↓
NavigationLink(destination: EmptyView()) {
//FontDetailView()はあとで作るので、とりあえず変更します。

ここまで書けたら、いったんシミュレーターかお手持ちのデバイスで実行してみよう!(command + R)

たいち

たいち

フォントの詳細を表示するビュー

この画面でフォントをタップして詳細を見れる画面があれば便利ですよね。タップでフォントの詳細を見るための、FontDetailViewを作っていきましょう。

ビュー構造体を作ります。

sturct ContentView: View {
  //...省略
}

//追加
struct FontDetailView: View {

}

次に、ビューで使いたいプロパティを追加していきます。

struct FontDetailView: View {
    //追加
    @State private var fontSize = 15.0
    var fontName: String
}

fontSizeはフォントの大きさです。スライダーで値を変更することがある変数には、SwiftUIでは@Stateをつけるというルールがあります。(詳しくは状態変数で調べてみてね!)

fontNameの値はContentViewから渡されるので、値を入れる変数(箱)だけ用意してあげます。

struct FontDetailView: View {
    @State private var fontSize = 15.0
    var fontName: String
//この行から
    var body: some View {
        let board = UIPasteboard.general
        let generator = UINotificationFeedbackGenerator()
    }
//ここまで追加
}


iOSのクリップボード機能を使うときは、UIPasteboardクラスを使います。コピーやペーストはこのクラスが使われています。
boardという名前の定数に入れておきましょう

iPhoneやiPadで文字をコピー&ペーストする時に、その文字列とかを保存するところがクリップボードだよ

たいち

たいち

一部のデバイスで使える、Haptic FeedBack (触覚フィードバック)を使用するために、UINotificationFeedbackGeneratorクラスのインスタンスを生成します。

今度はgeneratorという名前の定数に入れましょう。

ここからはビューの見た目の部分を書いていきます。

//var body: some View { 
return VStack(alignment: .leading, spacing: 10) {
            ScrollView {
                Spacer()
                Text("\(fontName)")
                    .font(.custom(self.fontName, size: CGFloat(self.fontSize)))
                Text(
                    """
あのイーハトーヴォの
すきとおった風、
夏でも底に冷たさをもつ青いそら、
うつくしい森で飾られたモーリオ市、
郊外のぎらぎらひかる草の波。
祇辻飴葛蛸鯖鰯噌庖箸
ABCDEFGHIJKLM
abcdefghijklm
1234567890
"""
                )
                    .font(.custom(self.fontName, size: CGFloat(self.fontSize)))
                    .frame(width: UIScreen.main.bounds.width)
                Spacer()
            }
            Text("FontSize: \(Int(self.fontSize))")
            Slider(value: self.$fontSize, in: 1.0...100.0)
            Button(action: {
                board.string = self.fontName
                generator.notificationOccurred(.success)
            }) {
                RoundedRectangle(cornerRadius: 10)
                    .frame(height: 60)
                    .foregroundColor(.primary)
                    .opacity(0.1)
                    .overlay(
                        Text("クリップボードにコピーする")
                            .foregroundColor(.secondary)
                )
            }
        }
        .padding()
        .onAppear {
            generator.prepare()
            //Haptic FeedBackを待機状態にする
        }
        .navigationBarTitle(Text("\(fontName)").font(.body), displayMode: .inline)
//}

上から解説します。

VStack {
  //縦に積み上げる
}

//カッコ内のテキストやボタンなどを縦(上下)に積み上げます。

 

VStackって?

こちらでHStackなどの一緒に解説しているよ!

たいち

たいち

Text(
"""
  //...省略
"""
)
.font(.custom(self.fontName, size: CGFloat(self.fontSize)))
//テキストのフォントとサイズを指定しています。
//フォントサイズを変数に入れているので、次に作るスライダーを動かすとサイズも動的に変化します。

“”” “””で挟んだテキストは勝手に複数行で表示される特殊な文字列です。

フォントのサイズを変えるためのスライダー

たかし

たかし

フォントサイズを大きくして細かい部分までみたい時や、逆に小さくして文章全体の雰囲気も見たい時はどうするの?

フォントサイズを大きくして細かい部分までみたい時や、逆に小さくして文章全体の雰囲気も見たい時があると思います。
そのため、フォントサイズをユーザーが変えるためのパーツを書いていきます。

//Text(
"""
/*省略*/
"""
    )
// .font(.custom(self.fontName, size: CGFloat(self.fontSize)))
//ここから下追加
Spacer()
Text("FontSize: \(Int(self.fontSize))")
Slider(value: self.$fontSize, in: 1.0...100.0)

上から順に、

  • パーツの間を広げるSpacer()、
  • フォントサイズを表示するText()、
  • フォントサイズを1.0から100.0の間で変化させるスライダー Slider()

を配置しています。

フォントの名前をクリップボードにコピーするボタン

フォントの名前で調べ物をしたり、そのまま入力したいときに便利な機能を追加で実装してみましょう。
クリップボードにコピーするには、ここで実装した boardを使います。(中身はUIPasteboard.general)

Button(action: {
    board.string = self.fontName
    generator.notificationOccurred(.success)
}) {
    RoundedRectangle(cornerRadius: 10)
        .frame(height: 60)
        .foregroundColor(.primary)
        .opacity(0.1)
        .overlay(
            Text("クリップボードにコピーする")
                .foregroundColor(.secondary)
        )
}

ボタンをタップしたときの動作はaction: {}のカッコ内に書きます。

今回はクリップボードにフォントの名前を保存し、Haptic FeedBackを使うので、

Button(action: {
    board.string = self.fontName
    generator.notificationOccurred(.success)
}) { 
//省略
}

とします。

generator.notificationOccured(.success)

というコードでHaptic FeedBackを発生させます。

Xcodeのシミュレーターではこの機能はないので、実機でこのコードを実行すると、デバイスがブルっと振動するのがわかると思います。

Button(action: {
//省略
}) {
//ボタン本体の見た目
}

最後のカッコ内には、ボタン本体の見た目を設定します。
今回は角丸の長方形に、テキストをオーバーレイ(上に重ねる)してみました。

これでほぼ完成です。

SwiftUIのソースコード

最後に、ビューの調整や上部のテキストを追加して、完成したコードはこちらになります。


import SwiftUI

struct ContentView: View {
    let familyNames = UIFont.familyNames
    
    var body: some View {
        let board = UIPasteboard.general
        return NavigationView {
            List {
                Text("Fonts Count: \(self.getFontNames().count)")
                ForEach(self.getFontNames(), id: \.self) { fontName in
                    NavigationLink(destination: FontDetailView(fontName: fontName)) {
                        Text("ABCDEFG:" + fontName)
                            .font(Font.custom(fontName, size: 18))
                            .foregroundColor(.primary)
                    }
                }
            }
            .navigationBarTitle( Text("All Fonts") )
            
        }
        .onAppear {
            board.prepareForInterfaceBuilder()
        }
    }
    
    func getFontNames() -> [String] {
        var fontNames: [String] = []
        for familyName in self.familyNames {
            for fontName in UIFont.fontNames(forFamilyName: familyName) {
                fontNames.append(fontName)
            }
        }
        return fontNames
    }
}

struct FontDetailView: View {
    @State private var fontSize = 15.0
    var fontName: String
    var body: some View {
        let board = UIPasteboard.general
        let generator = UINotificationFeedbackGenerator()
        return VStack(alignment: .leading, spacing: 10) {
            ScrollView {
                Spacer()
                Text("\(fontName)")
                    .font(.custom(self.fontName, size: CGFloat(self.fontSize)))
                Text(
                    """
あのイーハトーヴォの
すきとおった風、
夏でも底に冷たさをもつ青いそら、
うつくしい森で飾られたモーリオ市、
郊外のぎらぎらひかる草の波。
祇辻飴葛蛸鯖鰯噌庖箸
ABCDEFGHIJKLM
abcdefghijklm
1234567890
"""
                )
                    .font(.custom(self.fontName, size: CGFloat(self.fontSize)))
                    .frame(width: UIScreen.main.bounds.width)
                Spacer()
            }
            Text("FontSize: \(Int(self.fontSize))")
            Slider(value: self.$fontSize, in: 1.0...100.0)
            Button(action: {
                board.string = self.fontName
                generator.notificationOccurred(.success)
            }) {
                RoundedRectangle(cornerRadius: 10)
                    .frame(height: 60)
                    .foregroundColor(.primary)
                    .opacity(0.1)
                    .overlay(
                        Text("クリップボードにコピーする")
                            .foregroundColor(.secondary)
                )
            }
        }
        .padding()
        .onAppear {
            generator.prepare()
            //Haptic FeedBackを待機状態にする
        }
        .navigationBarTitle(Text("\(fontName)").font(.body), displayMode: .inline)
    }
}

フォントの一覧って眺めるだけでも楽しいし、デバイスで使えるフォントを把握しておくことで、今後何かを作るときのヒントにもなります!

たいち

たいち

最初からまた見返したいときはこちらをクリックしてください

最後まで読んでくれてありがとうございます。

関連記事

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です