[SwiftUI] UIFontPickerViewControllerをSwiftUIで使う

3 min read読了の目安(約2700字

まず包みます。

FontPicker.swift
struct FontPicker: UIViewControllerRepresentable {
    let configuration: UIFontPickerViewController.Configuration
    @Binding var pickerResult: Font
    @Binding var isPresented: Bool

    func makeUIViewController(context: Context) -> UIFontPickerViewController {
        let controller = UIFontPickerViewController(configuration: configuration)
        controller.delegate = context.coordinator
        return controller
    }

    func updateUIViewController(_ uiViewController: UIFontPickerViewController, context: Context) {

    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, UIFontPickerViewControllerDelegate {
        private let parent: FontPicker

        init(_ parent: FontPicker) {
            self.parent = parent
        }
        func fontPickerViewControllerDidPickFont(_ viewController: UIFontPickerViewController) {
            guard let descriptor = viewController.selectedFontDescriptor else { return }
            self.parent.pickerResult = Font.custom((descriptor.fontAttributes[.family] as? String) ?? descriptor.postscriptName, size: 16, relativeTo: .body)
            self.parent.isPresented = false
        }
    }
}

あとはViewで使うだけです。

ContentView.swift
struct FontPickView: View {
    @State private var isFontPickerPresented = false
    @State var selectedFont: Font = .body

    var fontPickerConfig: UIFontPickerViewController.Configuration {
        let config = UIFontPickerViewController.Configuration()
        config.displayUsingSystemFont = false
        config.includeFaces = true
        return config
    }

    var body: some View {
        VStack{
            Button{
                isFontPickerPresented = true
            } label: {
                Text("フォントを選択")
            }
            Text("テキスト Text").font(selectedFont)
        }
        .sheet(isPresented: $isFontPickerPresented){
            FontPicker(
                configuration: .init(),
                pickerResult: $selectedFont,
                isPresented: $isFontPickerPresented
            )
        }
    }
}

注意事項として、ユーザがApp Storeのアプリ経由であったり.mobileconfigファイルの利用であったりする方法で追加したフォントは、これだけでは選択できません。これを確かめるためには、例えばFontInstall.appなどをご利用下さい。

https://fontinstall.app/
ユーザのインストールしたフォントを利用可能にするにはCapabilityを追加する必要があります。

Target>Signing&Capabilities>+Capability>Fonts

でCapabilityを追加し、Use Installed Fontsにチェックを入れてください。
image
この状態でビルドすると、FontInstall.app経由でダウンロードしたフォントが選択可能になります。

参考

https://www.hackingwithswift.com/example-code/uikit/how-to-let-users-choose-a-font-with-uifontpickerviewcontroller
https://qiita.com/lcr/items/f9e98f76a48af0920bb1