struct
私は、ビューの配列を受け入れ、VStack
それらのビューがすべて斜めに積み重ねられていることを除いてそれらのビューを含む通常のものを返すシンプルなものを作成しようとしています。
コード:
struct LeaningTower<Content: View>: View {
var views: [Content]
var body: some View {
VStack {
ForEach(0..<views.count) { index in
self.views[index]
.offset(x: CGFloat(index * 30))
}
}
}
}
これはうまく機能しますが、これを呼び出す必要があるたびにいつもイライラします。
LeaningTower(views: [Text("Something 1"), Text("Something 2"), Text("Something 3")])
このように配列にビューをリストすることは非常に奇妙に思えるので、次のように構造体@ViewBuilder
を呼び出す方法があるかどうか疑問に思いました。LeaningTower
LeaningTower { // Same way how you would create a regular VStack
Text("Something 1")
Text("Something 2")
Text("Something 3")
// And then have all of these Text's in my 'views' array
}
ビューの配列を作成/抽出する方法があれば@ViewBuilder
教えてください。
(たとえそれが不可能であっても、@ViewBuilder
見た目をきれいにするあらゆる手段を使うと大いに役立ちます)
ベストアンサー1
ビューを抽出する必要があることはまれです配列@ViewBuilder
コンテンツをビューに渡すだけの場合は、次の操作を実行するだけです。
struct ContentView: View {
var body: some View {
VStackReplica {
Text("1st")
Text("2nd")
Text("3rd")
}
}
}
struct VStackReplica<Content: View>: View {
@ViewBuilder let content: () -> Content
var body: some View {
VStack(content: content)
}
}
これがあなたのユースケースに十分でない場合は、以下を参照してください。
推奨: 私のビュー抽出このパッケージは、ここでのコードよりもはるかに堅牢です。
汎用バージョンが動作しているので、異なる長さのタプルに対して複数の初期化子を作成する必要はありません。さらに、ビューは任意のものにすることができます (すべてがView
同じ型である必要はありません)。
私がこのために作ったSwiftパッケージは、ジョージ・エルシャム/ViewExtractorこの回答は簡略化された基本バージョンに過ぎないため、この回答の内容よりも多くの内容が含まれています。コードはこの回答と若干異なるため、README.md
例として最初の回答を読んでください。
答えに戻って、使用例:
struct ContentView: View {
var body: some View {
LeaningTower {
Text("Something 1")
Text("Something 2")
Text("Something 3")
Image(systemName: "circle")
}
}
}
ビューの定義:
struct LeaningTower: View {
private let views: [AnyView]
init<Views>(@ViewBuilder content: @escaping () -> TupleView<Views>) {
views = content().getViews
}
var body: some View {
VStack {
ForEach(views.indices) { index in
views[index]
.offset(x: CGFloat(index * 30))
}
}
}
}
TupleView
拡張機能(つまり、すべての魔法が起こる場所):
extension TupleView {
var getViews: [AnyView] {
makeArray(from: value)
}
private struct GenericView {
let body: Any
var anyView: AnyView? {
AnyView(_fromValue: body)
}
}
private func makeArray<Tuple>(from tuple: Tuple) -> [AnyView] {
func convert(child: Mirror.Child) -> AnyView? {
withUnsafeBytes(of: child.value) { ptr -> AnyView? in
let binded = ptr.bindMemory(to: GenericView.self)
return binded.first?.anyView
}
}
let tupleMirror = Mirror(reflecting: tuple)
return tupleMirror.children.compactMap(convert)
}
}
結果: