目も腰も痛い。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にラッピングして返してもらうのが一番スムーズでした。
.sheet(isPresented: $showDict){
let refLibVC = UIReferenceLibraryViewController.init(term: "text")
DictView(refLibVC: refLibVC)
}
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で表示するにはシンプルな方がよかったので、下のコードを追加してこいつらを取り除きます。
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()
//(中略)
}
//(中略)
}
//再帰的?にすべての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を追加。
.padding(.top,-55)
.presentationDetents([.medium,.large])
ここまで作ると結構いい感じにできます。
もともとこんなに止まっていたのが以下のようにスムーズになりました。やはりUIReferenceLibraryViewControllerを渡してあげるのがいいのかとおもいます。
参考:
https://qiita.com/shtnkgm/items/fac2756599b3dfcb7aa2