我正在尝试将数据从ScrollView的组件传递到模式。在这种情况下,我要传递的数据为image
。我的方法是每次单击ShelterView
时都要更新状态。
有数据传递到ShelterViewDetailed
,但仅以某种方式传递到ForEach
-循环的最后一个item.background
。换句话说,无论单击什么ShelterView
-始终显示最后一个item.background
。
有什么建议吗?
struct HomeList: View {
@State var showContent = false
@State var image = ""
var shelters = SheltersData
var body: some View {
VStack() {
HStack {
HomeListTitle()
Spacer()
}
.padding(.leading, 40)
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 35) {
ForEach(shelters) { item in
ShelterView(title: item.title, background: item.background)
.onTapGesture {
self.showContent.toggle()
self.image = item.background
}
.sheet(isPresented: self.$showContent)
{ ShelterDetailedView(image: self.image) }
}
}
.padding(.leading, 40)
.padding(.trailing, 40)
.padding(.bottom, 60)
Spacer()
}
}
}
}
struct ShelterDetailedView: View {
var image: String
var body: some View {
ZStack {
BlurView(style: .extraLight)
VStack {
Image(image)
.resizable()
.frame(width: UIScreen.main.bounds.width, height: 300)
Spacer()
}
}
}
}
编辑:
struct ShelterView: View {
var title: String?
var background: String?
var body: some View {
VStack {
Text(title ?? "")
.font(Font.custom("Helvetica Now Display Bold", size: 30))
.foregroundColor(.white)
.padding(15)
.lineLimit(2)
Spacer()
}
.background(
Image(background ?? "")
.brightness(-0.11)
.frame(width: 255, height: 360)
)
.frame(width: 255, height: 360)
.cornerRadius(30)
.shadow(color: Color("shadow"), radius: 10, x: 0, y: 10)
}
}
struct ShelterStruct: Identifiable {
var id: Int
var title: String
var background: String
}
let SheltersData = [
ShelterStruct(id: 1, title: "One", background: "pacific"),
ShelterStruct(id: 2, title: "Two", background: "second"),
ShelterStruct(id: 3, title: "Three", background: "ccc")
]
答案 0 :(得分:1)
更新:
所以这里的主要问题是您的图像(我打赌)比您放入的255宽度帧宽得多。通常这不是问题,因为您正确地使用了框架来限制可见尺寸。但是,事实证明,onTapGesture甚至可以在视图的超出可见框架的部分上识别出拍子。
在下面的示例中,我对您的视图进行了一些重构,您还可以看到,我正在将ShelterView的contentView强制设置为Rectangle()
,它应该很好地环绕框架。 onTapGesture低于此位置,因此,您的点击被限制为激活位于Rectangle范围内的视图。
还要注意,我将.sheet移到了ForEach循环之外。您只需要一个模态。
我最后的想法是,这比获得恕我直言的权利要难得多。仅通过打开视图调试器,我才意识到问题出在触摸目标上,这并不是SwiftUI或更严重的问题。话虽这么说,但我正在将其用于生产产品中,并且除这些以外,真的很喜欢它。
struct HomeList: View {
@State var showContent = false
@State var selectedShelter: ShelterStruct? = nil
var shelters = SheltersData
var body: some View {
VStack() {
HStack {
Text("Home List Title")
Spacer()
}
.padding(.leading, 40)
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 35) {
ForEach(shelters, id: \.id) { item in
ShelterView(shelter: item)
.contentShape(Rectangle())
.onTapGesture {
print("Tap")
self.selectedShelter = item
}
}
}
.padding(.leading, 40)
.padding(.trailing, 40)
.padding(.bottom, 60)
Spacer()
}
.sheet(item: self.$selectedShelter) { shelter in
ShelterDetailedView(image: shelter.background)
}
}
}
}
struct ShelterDetailedView: View {
var image: String
var body: some View {
ZStack {
VStack {
Image(image)
.resizable()
.frame(width: UIScreen.main.bounds.width, height: 300)
Spacer()
}
}
}
}
struct ShelterView: View {
var shelter: ShelterStruct
var body: some View {
VStack {
Text(shelter.title)
.font(Font.custom("Helvetica Now Display Bold", size: 30))
.foregroundColor(.white)
.padding(15)
.lineLimit(2)
Spacer()
}
.background(
Image(shelter.background)
.resizable()
.aspectRatio(1, contentMode: .fill)
.brightness(-0.11)
.frame(width: 255, height: 360)
)
.frame(width: 255, height: 360)
.cornerRadius(30)
.shadow(color: .gray, radius: 10, x: 0, y: 10)
}
}
struct ShelterStruct: Identifiable {
var id: Int
var title: String
var background: String
}
let SheltersData = [
ShelterStruct(id: 1, title: "One", background: "pacific"),
ShelterStruct(id: 2, title: "Two", background: "second"),
ShelterStruct(id: 3, title: "Three", background: "ccc")
]
要花一些时间才能习惯SwiftUI的工作方式。这里发生的是,您正在更改 ForEach 循环中的 @State图像,该循环在实例化正文时将进行评估。这意味着您的州将快速遍历每个可用州,并最终确定住所中的最终形象。
然后,当您点击任何行时,切换Bool,然后该工作表将显示当前图像状态,这将是最后一个状态。
您需要做的是为selectedImage提供一个可选的@State:
@State private var selectedImage: String? = nil
然后您可以使用这种形式的工作表:
.sheet(item: $selectedImage) {
为了显示它,您有这个:
.onTapGesture {
self.selectedImage = item.background
}
请注意,在这种情况下,您将使用 ForEach 循环中的项目的闭包变量,而不是使用 @State 。
关闭工作表后,SwiftUI将为您将绑定的 selectedImage 更新回 nil ,从而保持视图状态正确。
答案 1 :(得分:0)
我想我找到了您的问题。
// ForEach(shelters) { item in
我不知道这里的值是什么:SheltersData。
但是通常,当人们使用一些数组值时,他们更喜欢像以下这样使用:
ForEach(shelters, id: \.title) { item in
您应该使用id
来标识项目。
struct SheltersData{
var title: String
var background: String
}
var shelters : [SheltersData] = [SheltersData(title: "cool", background: "image2"),
SheltersData(title: "hot", background: "image1")]
如果两个标题都相同,您将始终像以前一样看到最后一个背景。
因此,我建议您向ForEach结构中添加不同的id
。