1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

iOS内蔵辞書を見れるUIReferenceLibraryViewControllerをSwiftUIから触る

Last updated at Posted at 2022-11-26

目も腰も痛い。Swift歴2週間の松本です。
UIReferenceLibraryViewControllerに関する日本語の記事はこれで4件目です。(私調べ)
みなさんもっと使ってください。
現在Swiftの勉強のために辞書アプリを作っていますが、Appleの公式ガイドラインには

A UIReferenceLibraryViewController object should not be used to display wordlists, create a standalone dictionary app, or republish the content in any form.

とあるので、AppStoreではこのクラスを使った辞書アプリは公開できませんね。

今回このクラスを使うに当たり素人には難しい点がいくつかあったのでまとめておきます。

まず、UIKitであること。SwiftUIの中でUIViewを使うには
UIViewRepresentableまたはUIViewControllerRepresentableを介する必要があります。
色々試しましたがmodal viewの.sheetと組み合わせても表示がモタつかないようにするには、
呼び出し元のContentView.swiftで辞書のViewControllerを作り、それをUIViewRepresentableに渡してSwiftUIの扱えるViewにラッピングして返してもらうのが一番スムーズでした。

ContentView.swift
 .sheet(isPresented: $showDict){
                        let refLibVC = UIReferenceLibraryViewController.init(term: "text")
                        DictView(refLibVC: refLibVC)
                    }
DictView.swift
struct DictView: UIViewRepresentable{
        var refLibVC:UIReferenceLibraryViewController
        func makeUIView(context: Context) -> some UIView {  
        let uiLayoutContainerView = refLibVC.view.findViews(subclassOf: UIView.self)        

        return refLibVC.view
    }
    func updateUIView(_ uiView: UIViewType, context: Context) {}
}

ただし、こいつが作ってくれるViewControllerにはおせっかいにもNavigationBarとToolBarも含まれます。modal viewで表示するにはシンプルな方がよかったので、下のコードを追加してこいつらを取り除きます。

DictView.swift
struct DictView: UIViewRepresentable{
//(中略)
func makeUIView(context: Context) -> some UIView {  
        //(中略)
        //内蔵辞書のナビゲーションバー,ツールバーを除去する。 
        let navigationBar = refLibVC.view.findViews(subclassOf: UINavigationBar.self).first
        navigationBar!.removeFromSuperview()
        let toolBar = refLibVC.view.findViews(subclassOf: UIToolbar.self).first
        toolBar!.removeFromSuperview()
        //(中略)
    }
//(中略)
}
DictView.swift
//再帰的?にすべてのSubViewを見つけてきてくれる関数、神。
extension UIView {
    func findViews<T: UIView>(subclassOf: T.Type) -> [T] {
        /*<T: UIView>この表記はジェネリクス関数であることを表す。
         ローマ字は何でも良いが、ここではT。引数はUIView以下のクラスの型。返り値はクラス?*/
        return recursiveSubviews.compactMap { $0 as? T }
        //compactMapに関してはまた今度調べよう!
    }
    
    var recursiveSubviews: [UIView] {
        return subviews + subviews.flatMap { $0.recursiveSubviews }
        //flatmapってなんだよ!
    }
}

あとは、ナビゲーションバー,ツールバーを取っ払った分のズレの解消と、セミモーダル(iOS16以降)の実現のために呼び出し元に以下のmodifierを追加。

ContentView.swift
 .padding(.top,-55)
 .presentationDetents([.medium,.large])

ここまで作ると結構いい感じにできます。
ezgif-3-27d17a631c.gif
もともとこんなに止まっていたのが以下のようにスムーズになりました。やはりUIReferenceLibraryViewControllerを渡してあげるのがいいのかとおもいます。

ezgif-3-1742b397e4.gif

参考:
https://qiita.com/shtnkgm/items/fac2756599b3dfcb7aa2

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?