78032


## 質問

SwiftUIのボタンなどを動的に追加したのですが、その方法がわかりません。

やりたい動きとしては、上のボタンで、値変更  
下のボタンで、新たにボタン(UI)を追加するといったものです。

## UI

![](https://i.stack.imgur.com/QCHB0.png)

## コード

[code]

    import SwiftUI
    
    struct Climate: View {
        @State var humid = 67
        @State var temperature = 76
        @State var lightness = 45
        
        var body: some View {
            VStack {
                ClimateData("照度", lightness)
                ClimateData("温度", temperature)
                ClimateData("湿度", humid)
                
                Button(
                    action: {
                        self.humid = 123
                    }, label: {
                    Text("湿度変更")
                })
                
                Button(
                    action: {
                        // 新たなClimateDataを追加
                    }, label: {
                    Text("新たなClimateDataを追加")
                })
            }
        }
    }
    
    struct Climate_Previews: PreviewProvider {
        static var previews: some View {
            Climate()
        }
    }
    
    struct ClimateData: View {
        @State var name: String
        @State var value: Int
        
        init(_ name: String, _ value: Int) {
            self.name = name
            self.value = value
        }
        
        var body: some View {
            HStack{
                Text(name)
                Text((String(value)))
            }
        }
    }
    
[/code]


CC BY-SA 4.0
2021-07-07T14:08:40.287
78029
2021-07-07T23:43:37.810
40856
question
swift swiftui
SwiftUIのボタンなどを動的に追加したのですが、その方法がわかりません。


SwiftUIはUIを宣言的に表現すること、つまりview階層もソースコード中に「宣言」的に現すことを目指したUIフレームワークですので、ボタンなどのUI要素を任意のview階層に動的に追加することは出来ません。

UIKitでは簡単に出来ていたことですが、SwiftUIでアプリを作るのであれば発想を変える(もしかしたら提供するアプリの機能そのものを見直す)必要があるでしょう。

「ボタンなど」と書かれていて、どんな機能のボタンなのか、ボタン以外にどんなものを想定しているのかがわからないので、あまり実用的な例は書けませんが、例えば次のようなことなら可能です。

[code]

    import SwiftUI
    
    struct ButtonItem: Identifiable {
        let id = UUID()
        let title: String
        let action: ()->Void
    }
    
    struct Climate: View {
        @State var humid = 67
        @State var temperature = 76
        @State var lightness = 45
        
        @State var buttonItems: [ButtonItem] = []
        
        var body: some View {
            VStack {
                ClimateData("照度", lightness)
                ClimateData("温度", temperature)
                ClimateData("湿度", humid)
                
                ForEach(buttonItems) { item in
                    Button(
                        action: item.action,
                        label: {
                            Text(item.title)
                    })
                }
                
                Button(
                    action: {
                        self.buttonItems.append(
                            ButtonItem(
                                title: "温度変更",
                                action: {
                                self.temperature = 100
                            })
                        )
                    }, label: {
                    Text("新たなClimateDataを追加")
                })
            }
            .onAppear {
                self.buttonItems.append(
                    ButtonItem(
                        title: "湿度変更",
                        action: {
                        self.humid = 123
                    })
                )
            }
        }
    }
    
[/code]


CC BY-SA 4.0
2021-07-07T23:43:37.810
78032
2021-07-07T23:43:37.810
13972
78029
answer