Martin'in dediği gibi , VStack
's belgelerine bakarsanız init(alignment:spacing:content:)
, content:
parametrenin özniteliğe sahip olduğunu görebilirsiniz @ViewBuilder
:
init(alignment: HorizontalAlignment = .center, spacing: Length? = nil,
@ViewBuilder content: () -> Content)
Bu öznitelik ViewBuilder
, üretilen arayüze bakarsanız şöyle görünen türü ifade eder :
@_functionBuilder public struct ViewBuilder {
public static func buildBlock() -> EmptyView
public static func buildBlock(_ content: Content) -> Content
where Content : View
}
Bu @_functionBuilder
özellik, burada Swift evrimine değinilen ve SwiftUI'de kullanılmasına olanak tanıyan Xcode 11 ile birlikte gelen Swift sürümü için özel olarak uygulanan " işlev oluşturucular " adlı resmi olmayan bir özelliğin bir parçasıdır .
Bir türün işaretlenmesi @_functionBuilder
, bunun işlevler, hesaplanan özellikler ve bu durumda işlev türünün parametreleri gibi çeşitli bildirimlerde özel bir öznitelik olarak kullanılmasına izin verir. Bu tür açıklamalı bildirimler, kod bloklarını dönüştürmek için işlev oluşturucuyu kullanır:
- Açıklamalı fonksiyonlar için, dönüştürülen kod bloğu gerçeklemedir.
- Açıklamalı hesaplanmış özellikler için, dönüştürülen kod bloğu alıcıdır.
- İşlev türünün açıklamalı parametreleri için, dönüştürülen kod bloğu, kendisine iletilen herhangi bir kapatma ifadesidir (varsa).
Bir işlev oluşturucunun kodu dönüştürme yolu , bir dizi ifadeyi alan ve bunları tek bir değerde birleştiren gibi oluşturucu yöntemlerin uygulanmasıyla tanımlanır buildBlock
.
Örneğin, birden çok görünümü tek bir görüntüde birleştirerek 1 ila 10 uyumlu parametreyi ViewBuilder
uygular :buildBlock
View
TupleView
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
extension ViewBuilder {
public static func buildBlock<Content>(_ content: Content)
-> Content where Content : View
public static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1)
-> TupleView<(C0, C1)> where C0 : View, C1 : View
public static func buildBlock<C0, C1, C2>(_ c0: C0, _ c1: C1, _ c2: C2)
-> TupleView<(C0, C1, C2)> where C0 : View, C1 : View, C2 : View
}
Bu, VStack
başlatıcıya geçirilen bir kapanış içindeki bir dizi görünüm ifadesinin buildBlock
aynı sayıda argümanı alan bir çağrıya dönüştürülmesine izin verir . Örneğin:
struct ContentView : View {
var body: some View {
VStack(alignment: .leading) {
Text("Hello, World")
Text("Hello World!")
}
}
}
bir çağrıya dönüşür buildBlock(_:_:)
:
struct ContentView : View {
var body: some View {
VStack(alignment: .leading) {
ViewBuilder.buildBlock(Text("Hello, World"), Text("Hello World!"))
}
}
}
sonuçlanan opak sonuç türü some View
karşılanmaktaydı TupleView<(Text, Text)>
.
ViewBuilder
Yalnızca buildBlock
en fazla 10 parametreyi tanımladığını unutmayın , bu nedenle 11 alt görünüm tanımlamaya çalışırsak:
var body: some View {
VStack(alignment: .leading) {
Text("Hello, World")
Text("Hello World!")
Text("Hello World!")
Text("Hello World!")
Text("Hello World!")
Text("Hello World!")
Text("Hello World!")
Text("Hello World!")
Text("Hello World!")
Text("Hello World!")
Text("Hello World!")
}
}
Bu kod bloğunu işleyecek bir oluşturucu yöntemi olmadığından bir derleyici hatası alıyoruz (bu özellik hala devam eden bir çalışma olduğundan, etrafındaki hata mesajlarının o kadar yararlı olmayacağını unutmayın).
Gerçekte, insanların bu kısıtlamaya sık sık maruz kalacağına inanmıyorum, örneğin yukarıdaki örnek, ForEach
bunun yerine görünüm kullanılarak daha iyi sunulacaktır :
var body: some View {
VStack(alignment: .leading) {
ForEach(0 ..< 20) { i in
Text("Hello world \(i)")
}
}
}
Bununla birlikte, 10'dan fazla statik olarak tanımlanmış görünüme ihtiyacınız varsa, Group
görünümü kullanarak bu kısıtlamayı kolayca çözebilirsiniz :
var body: some View {
VStack(alignment: .leading) {
Group {
Text("Hello world")
}
Group {
Text("Hello world")
}
}
ViewBuilder
ayrıca aşağıdaki gibi diğer işlev oluşturucu yöntemlerini de uygular:
extension ViewBuilder {
public static func buildEither<TrueContent, FalseContent>(first: TrueContent)
-> ConditionalContent<TrueContent, FalseContent>
where TrueContent : View, FalseContent : View
public static func buildEither<TrueContent, FalseContent>(second: FalseContent)
-> ConditionalContent<TrueContent, FalseContent>
where TrueContent : View, FalseContent : View
}
Bu, ona if ifadelerini işleme yeteneği verir:
var body: some View {
VStack(alignment: .leading) {
if .random() {
Text("Hello World!")
} else {
Text("Goodbye World!")
}
Text("Something else")
}
}
hangisine dönüşür:
var body: some View {
VStack(alignment: .leading) {
ViewBuilder.buildBlock(
.random() ? ViewBuilder.buildEither(first: Text("Hello World!"))
: ViewBuilder.buildEither(second: Text("Goodbye World!")),
Text("Something else")
)
}
}
(gereksiz 1 argüman yayarak ViewBuilder.buildBlock
netlik çağrısı yapar ).
@ViewBuilder
geliştirici.apple.com/ documentation/swiftui/viewbuilder olduğunu gösterir .