【Swift UI】@ViewBuilderの使い方!カスタムスタックとTupleView型
この記事からわかること
- Swift UIの@ViewBuilderとは?
- 役割と使い方
- TupleViewとは
- ビューを複数構築する方法
- Function declares an opaque return type, but has no return statements in its body from which to infer an underlying typeとは?
- カスタムスタックビューの実装する方法
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
@ViewBuilderとは?
@resultBuilder
struct ViewBuilder
Swift UIの@ViewBuilder
属性とはクロージャから階層構造のビューを構築するためのResult Builderです。クロージャの前に付与して使用します。
func simpleView() -> some View{
Image(systemName: "iphone")
}
通常クロージャが返すのは1つのビュー(値)だけですが、@ViewBuilder
を付与したクロージャは複数のビューを1つのビューとみなして返すことができます。
@ViewBuilder
func multiView() -> some View{
Image(systemName: "iphone")
Image(systemName: "iphone")
Image(systemName: "iphone")
}
Function declares an opaque return type, but has no return statements in its body from which to infer an underlying type
@ViewBuilder
を外して以下のように実装しようとすると、Function declares an opaque return type, but has no return statements in its body from which to infer an underlying type
というエラーが発生します。
func mulchView() -> some View{
Image(systemName: "iphone")
Image(systemName: "iphone")
Image(systemName: "iphone")
}
エラーが発生しないようにするにはGroup
やStack
などで囲って1つのビューにする必要があります。
func doubleView() -> some View{
Group{
Image(systemName: "iphone")
Image(systemName: "iphone")
}
}
TupleView型
Button {
let multi = multiView()
let double = doubleView()
print(type(of: multi))
print(type(of: double))
} label: {
Text("Button")
}
// 結果:TupleView<(Image, Image, Image)>
// 結果:Group<TupleView<(Image, Image)>>
@ViewBuilder
を使用して返されるのはTupleView
型です。異なる型を保持することができるタプルのような特性としてビューを保持するデータ型です。
おすすめ記事:タプルとは?使い方や注意点
使われているところ
@ViewBuilder
はSwift UIのさまざまなところで使用されています。例えばView
プロトコルのbody
プロパティやStack
のイニシャライザなど複数のビューを記述できる箇所に使用されていることが多いです。
public protocol View {
associatedtype Body : View
@ViewBuilder var body: Self.Body { get }
}
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
@frozen public struct VStack<Content> : View where Content : View {
@inlinable public init(
alignment: HorizontalAlignment = .center,
spacing: CGFloat? = nil,
@ViewBuilder content: () -> Content
)
public typealias Body = Never
}
カスタムスタックを実装する
@ViewBuilder
を使用することで間に任意のビューを挟める独自のコンテナビューを実装することができます。
言葉だけでは分かりにくいので一度使い方を見てみます。
struct CustomStack<Content: View>: View {
var content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
VStack(spacing:20) {
content
}
}
}
ここではCustomStack
構造体を定義し、プロパティとしてView
プロトコルに準拠したジェネリック型のContent
型を定義しています。
またインスタンス化時にContent
型を渡せるようにイニシャライザから初期値を格納できるようにしています。そしてイニシャライザの引数定義の際に@ViewBuilder
を付与します。
ここでの@ViewBuilder
の役割はクロージャ内で複数のビューを単一のビューとして扱えるようにすることです。
あとはbody
プロパティの中に実装したいコンテナビューを記述し、イニシャライザで渡されるcontent
プロパティを呼び出します。
定義したコンテナビューは以下のように使用できます。
struct ContentView: View {
var body: some View {
CustomStack { // 余白20のVStackと同じ
Text("Hello")
Text("World")
}
}
}
ご覧いただきありがとうございました。