【问题标题】:SwiftUI onTapGesture displays new viewSwiftUI onTapGesture 显示新视图
【发布时间】:2020-08-02 16:01:37
【问题描述】:

我正在使用 SwiftUI 制作我自己的披萨外卖应用程序。我现在卡住了,因为我不知道如何从数组中显示与他自己的索引相关的相同图像视图(包括比萨饼的描述)。而不是行{self.images print("ok")},我希望每次用户点击数组中的图像时,它都会显示带有简短文本描述的相同图像。我的问题描述是否足够清楚?如果有人能帮助我解决这个问题,我将不胜感激。非常感谢您阅读它。这是代码:

HStack {
    ForEach(images, id: \.id) { post in
        ForEach(0..<1) { _ in
            ImageView(postImages: post)
        }
    }
    Spacer()
}
.onTapGesture {
    self.images
    print("ok")
}
.navigationBarTitle("Choose your Pizza")
.padding()

【问题讨论】:

  • 您的问题不够清楚 - 您希望如何显示新视图?作为工作表,带有导航链接...?
  • 当触发“.onTapGesture”时,我希望数组中的每个图像在完全相同的页面上显示相同的图像。我知道我将不得不使用“位置属性”,但我不知道如何。请问有什么帮助吗? ????????????
  • 所以你有一个图像数组(开头没有描述),当用户点击特定图像时,你想显示这个图像及其描述 - 或者我错过了什么?
  • 是的,这正是我想做的!有什么想法吗?
  • 您希望它显示为现有图像数组的顶部的新窗口吗?还是只为所选图片添加一个描述行?

标签: view swiftui


【解决方案1】:

假设您的Item 有一个结构,您需要将其与Identifiable 保持一致:

struct Item: Identifiable {
    var id: String { name } // needed for `Identifiable`

    let name: String
    let imageName: String
    let description: String
}

然后在你的主视图中:

struct ContentView: View {
    let items = [
        Item(name: "item1", imageName: "circle", description: "some description of item 1"),
        Item(name: "item2", imageName: "circle", description: "some description of item 2"),
        Item(name: "item3", imageName: "circle", description: "some description of item 3"),
    ]

    @State var selectedItem: Item? // <- track the selected item

    var body: some View {
        NavigationView {
            HStack {
                ForEach(items, id: \.id) { item in
                    ImageView(imageName: item.imageName)
                        .onTapGesture { 
                            self.selectedItem = item // select the tapped item
                        }
                }
                Spacer()
            }
            .navigationBarTitle("Choose your Pizza")
            .padding()
        }
        .sheet(item: $selectedItem) { item in // show a new sheet if selectedItem is not `nil`
            DetailView(item: item)
        }
    }
}

如果您有图像的自定义视图:

struct ImageView: View {
    let imageName: String

    var body: some View {
        Image(systemName: imageName)
    }
}

您可以为您的项目创建详细视图(包含项目描述等):

struct DetailView: View {
    let item: Item

    var body: some View {
        VStack {
            Text(item.name)
            Image(systemName: item.imageName)
            Text(item.description)
        }
    }
}

编辑

这是使用相同视图显示图像或带有描述的图像的不同方法:

struct ContentView: View {
    @State var items = [
        Item(name: "item1", imageName: "circle", description: "some description of item 1"),
        Item(name: "item2", imageName: "circle", description: "some description of item 2"),
        Item(name: "item3", imageName: "circle", description: "some description of item 3"),
    ]

    var body: some View {
        NavigationView {
            HStack {
                ForEach(items, id: \.self) { item in
                    DetailView(item: item)
                }
                Spacer()
            }
            .navigationBarTitle("Choose your Pizza")
            .padding()
        }
    }
}
struct DetailView: View {
    @State var showDescription = false
    let item: Item

    var body: some View {
        VStack {
            Text(item.name)
            Image(systemName: item.imageName)
            if showDescription {
                Text(item.description)
            }
        }
        .onTapGesture {
            self.showDescription.toggle()
        }
    }
}

并将Item Hashable 一致:

struct Item: Hashable

或代替:

ForEach(items, id: \.self)

明确指定id

ForEach(items, id: \.name)

【讨论】:

  • 非常感谢您的贡献!不幸的是,这不是我想做的。
  • 因为一旦图像被点击,我就不会打开一个新窗口。我希望它在完全相同的页面中显示相同的图像(与其自己的数组索引相关),并带有简短的文本描述。所以基本上,我知道我必须在“onTapGesture”括号中使用“位置属性”。不过还是非常感谢你的回答。
  • @Momo 我相信你说过 我希望它在现有图像数组之上显示为一个新窗口。 无论如何,我已经添加了另一个解决方案。
  • 不幸的是,我知道这个问题“在 'ForEach' 上引用初始化程序 'init(_:id:content:)' 要求 'Item' 符合 'Hashable'”
  • @Momo 是的,我忘了将它添加到答案中 - 请参阅更新。
【解决方案2】:

我也尝试了一下,因为它的价值。

(顺便说一句,@pawello2222 的回答也是 100% 正确的。实现您所描述的方法不止一种)

我首先创建了一个披萨菜单(使用占位符图像):

Main pizza list view

从菜单中选择一个项目后,您将被带到所选的比萨详情:

Chosen pizza detail view

我使用NavigationViewNavigationLink 在视图之间导航。

这是完整的源代码(为了在 Swift Playgrounds 中运行获得最佳效果):


import PlaygroundSupport // For running in Swift Playground only
import SwiftUI

// The main pizza listing page (view)
struct PizzaList: View {
    
    // Array of pizza images
    let pizzaImages = [
        Image(systemName: "circle.fill"),
        Image(systemName: "square.fill"),
        Image(systemName: "triangle.fill")
    ]
    
    // Array of pizza descriptions
    let pizzaDescriptions = [
        "Circular Pizza",
        "Square Pizza",
        "Triangle Pizza"
    ]
    
    var body: some View {
        // Wrap in navigation view to be able to switch between "pages"
        NavigationView {
            VStack {
                ForEach(0 ..< pizzaImages.count) { index in
                    // Wrap in navigation link to provide a link to the next "page"
                    NavigationLink(
                        // This is the contents of the chosen pizza page
                        destination: PizzaDetail(
                            pizzaImage: self.pizzaImages[index],
                            description: self.pizzaDescriptions[index]
                        )
                    ) {
                        // This is an item on the main list
                        PizzaRow(
                            pizzaImage: self.pizzaImages[index],
                            description: self.pizzaDescriptions[index]
                        )
                    }
                }
            }
            .navigationBarTitle("Available Pizzas")
        }
        .navigationViewStyle(StackNavigationViewStyle())
    }
}

// Layout for each pizza item on the list
struct PizzaRow: View {
    
    let pizzaImage: Image
    let description: String
    
    var body: some View {
        HStack {
            Spacer()
            
            pizzaImage
                .resizable()
                .aspectRatio(contentMode: .fit)
                .foregroundColor(.orange)
            Spacer()
            
            Text(self.description)
            Spacer()
        }
        .padding()
    }
}

// Layout for the chosen pizza page
struct PizzaDetail: View {
    
    let pizzaImage: Image
    let description: String
    
    var body: some View {
        VStack {
            Spacer()
            Text(description)
                .font(.title)
            
            Spacer()
            
            pizzaImage
                .resizable()
                .aspectRatio(contentMode: .fit)
            Spacer()
        }
        .padding()
        .navigationBarTitle("Your Pizza Choice")
    }
}

// For Playgrounds only
PlaygroundPage.current.setLiveView(PizzaList())

【讨论】:

  • 与其创建两个单独的数组(pizzaImages、pizzaDescriptions),不如创建一个将所有内容组合在一起的结构。使用单独的数组,处理索引是有风险的 - 添加新图像时您可能很容易忘记添加描述。而且您只检查pizzaImages.count - 如果pizzaDescriptions.count 更小怎么办?
  • 非常感谢您的贡献。非常感谢您的贡献!不幸的是,这不是我想做的。因为一旦图像被点击,我就不会打开一个新窗口。我希望它在完全相同的页面中显示相同的图像(与它自己的数组索引相关),并带有简短的文本描述。所以基本上,我知道我必须在“onTapGesture”括号中使用“位置属性”。不过还是非常感谢你的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
  • 1970-01-01
  • 1970-01-01
  • 2022-07-11
  • 1970-01-01
  • 1970-01-01
  • 2020-03-23
相关资源
最近更新 更多