Reputation: 549
I have a ScrollView with a ForEach loop, each rendering a View. In the View I have 3 renders of the below ActionItem (a button that displays a sheet). The sheet does not show up with ScrollView but does with List. I'd normally attach the .sheet at the ScrollView layer however, with each button rendering a different view it seems more appropriate to nest it.
How I could get this to work with ScrollView? I'm using Xcode 12
struct ActionItem<Content>: View where Content : View {
public var text: String
public var icon: String
public var content: Content
@State var isPresented = false
init(text: String, icon: String, @ViewBuilder content: () -> Content) {
self.text = text
self.icon = icon
self.content = content()
}
var body: some View {
Button (action: {
DispatchQueue.main.async {
withAnimation {
self.isPresented = true
}
}
}) {
HStack(spacing: 2) {
Image(systemName: icon).font(.system(size: 14, weight: .semibold))
Text(text).fontWeight(.semibold)
}.padding([.top, .bottom], Dimensions.spacing)
.padding([.leading, .trailing], Dimensions.spacingMedium)
}.foregroundColor(Color.gray).font(.subheadline).background(Color.grayWhiteTer)
.cornerRadius(Dimensions.spacing)
.sheet(isPresented: $isPresented) {
self.content
}
}
}
In the View I'd render ActionItem such as Text, this also occurs if the View is ignored and the ActionItem is just directly in the ForEach. Same issue, sheet does not appear.
ActionItem(text: "", icon: "pencil") {
Text("ok")
}
The list looks like this
import SwiftUI
struct ItemsList: View {
@ObservedObject var itemModel: ItemModel
var body: some View {
VStack(alignment: .center, spacing: 0) {
ScrollView {
VStack {
ForEach(itemModel.items, id: \.self) { item in
ItemView(item: item)
}
}.frame(maxWidth: .infinity, maxHeight: .infinity)
}}
Suggested callback update
struct ActionItem<Content>: View where Content : View {
public var text: String
public var icon: String
public var content: () -> Content
@State var isPresented = false
init(text: String, icon: String, @ViewBuilder content: @escaping () -> Content) {
self.text = text
self.icon = icon
self.content = content
}
var body: some View {
Button (action: {
DispatchQueue.main.async {
withAnimation {
self.isPresented = true
}
}
}) {
HStack(spacing: 2) {
Image(systemName: icon).font(.system(size: 14, weight: .semibold))
Text(text).fontWeight(.semibold)
}.padding([.top, .bottom], Dimensions.spacing)
.padding([.leading, .trailing], Dimensions.spacingMedium)
}.foregroundColor(Color.gray).font(.subheadline).background(Color.grayWhiteTer)
.cornerRadius(Dimensions.spacing)
.sheet(isPresented: $isPresented) {
self.content()
}
}
}
Upvotes: 0
Views: 492
Reputation: 205
Try saving content as a callback (i.e. () -> Content) and call it in the sheet method instead of calling it in the initializer.. This will change when the view is created.
Upvotes: 1