SwiftUIでPreviewの内容が実体と異なる場合がある話
SwiftUIにおいて、そのView(A)のPreviewでは正しいのに、Aを使ったView(B)のPreviewでは正しくないという現象に遭遇した。
まずは結論から。
結論
同名のViewがあった場合に、Previewの場所によって異なるViewになるので、同名の構造体・クラスは明確に指定するべき。
発生条件と再現方法
再現コードを公開しているので、コード全体を見たい場合はこちらを参照してください。
public extension Form {
struct Group<Content: View>: View {
// 省略
}
}
public extension Form {
struct Announce<Content: View>: View {
private let content: Content
public init(@ViewBuilder content: () -> Content) {
self.content = content()
}
public var body: some View {
Group { // このGroupが`Form.Group`になるか`SwiftUI.Group`になるかが変わる
content
}
}
}
}
#Preview {
Form.Announce {
Text("Does it use SwiftUI.Group?")
}
}
ここでForm.Announce.body
内で使用されているGroup
は近いところに定義されている物が選ばれる為、Form.Group
となるはずだった。
しかし、このPreviewを確認してみると、SwiftUI.Group
が使用されている。
class ViewController: UIHostingController<AnyView> {
init() {
super.init(rootView: AnyView(Form.Announce {
Text("Does it use SwiftUI.Group?")
}))
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
次に、AnyViewでラップしてはいるが、同様の内容を実際に表示してみる。
すると、以下のような画面になり、先ほどとは見た目が異なる結果となる。これは、Form.Announce.body
内で使用されているGroup
がForm.Group
として解決された結果だ。
色々と試した結果、Previewは常にSwiftUIのViewを優先するということもないようで、何か他にも条件がありそうではある。
という訳で、同名の構造体・クラスには気をつけましょうという話でした。
記事が気に入ったらチップを送ることができます!
You can give me a cup of coffee :)
Kyash ID: soranoba
Amazon: Wish List
GitHub Sponsor: github.com/sponsors/soranoba
PayPal.Me: paypal.me/soranoba
(Updated: )