如何在SwiftUI(iOS14)中将可点击区域扩展到整个框架?

时间:2020-07-01 19:49:11

标签: swiftui

我正在尝试使用Swift 5.3制作一个VGrid,但是唯一可以点击的区域是矩形的上部。其他答案建议使用contentShape,但我也无法使之工作。如何使整个框架可轻敲?下面的代码:

import SwiftUI
import Combine
import Foundation

struct Item: Codable, Identifiable, Equatable {
    var id: Int
    var name: String
}

final class UserData: ObservableObject {
    @Published var items = Bundle.main.decode([Item].self, from: "data.json")
}

struct ContentView: View {
    @State var itemID = Item.ID()
    @StateObject var userData = UserData()
    let columns = [
        GridItem(.adaptive(minimum: 118))
    ]

    var body: some View {
        NavigationView {
            ScrollView {
                LazyVGrid(columns: columns) {
                    ForEach(userData.items) { item in
                        NavigationLink(destination: ContentDetail(itemID: item.id - 1)) {
                            ContentRow(item: item)
                        }
                    }
                }
            }
        }
    }
}

struct ContentRow: View {
    var item: Item
    
    var body: some View {
        VStack {
            GeometryReader { geo in
                ZStack{
                    VStack(alignment: .trailing) {
                        Text(item.name)
                            .font(.caption)
                    }
                }
                .padding()
                .foregroundColor(Color.primary)
                .frame(width: geo.size.width, height: 120)
                .border(Color.primary, width: 2)
                .cornerRadius(5)
                .contentShape(Rectangle())
            }
        }
    }
}

struct ContentDetail: View {
    @State var itemID = Item.ID()
    @StateObject var userData = UserData()

    var body: some View {
            Text(userData.items[itemID].name)
    }
}

extension Bundle {
    func decode<T: Decodable>(_ type: T.Type, from file: String, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .deferredToDate, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) -> T {
        guard let url = self.url(forResource: file, withExtension: nil) else {
            fatalError("Failed to locate \(file) in bundle.")
        }

        guard let data = try? Data(contentsOf: url) else {
            fatalError("Failed to load \(file) from bundle.")
        }

        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = dateDecodingStrategy
        decoder.keyDecodingStrategy = keyDecodingStrategy

        do {
            return try decoder.decode(T.self, from: data)
        } catch DecodingError.keyNotFound(let key, let context) {
            fatalError("Failed to decode \(file) from bundle due to missing key '\(key.stringValue)' not found – \(context.debugDescription)")
        } catch DecodingError.typeMismatch(_, let context) {
            fatalError("Failed to decode \(file) from bundle due to type mismatch – \(context.debugDescription)")
        } catch DecodingError.valueNotFound(let type, let context) {
            fatalError("Failed to decode \(file) from bundle due to missing \(type) value – \(context.debugDescription)")
        } catch DecodingError.dataCorrupted(_) {
            fatalError("Failed to decode \(file) from bundle because it appears to be invalid JSON")
        } catch {
            fatalError("Failed to decode \(file) from bundle: \(error.localizedDescription)")
        }
    }
}

还有JSON部分:

[
    {
        "id": 1,
        "name": "Example data",
    },
    {
        "id": 2,
        "name": "Example data 2",
    }
]

感谢您的帮助。这可能是SwiftUI中的错误吗?

2 个答案:

答案 0 :(得分:0)

尝试将contentShape放在ContentRow的最外层VStack上。您需要将contentShape放在展开的视图上以填充其父级(或父级),在您的情况下,我认为这是GeometryReader。 GeometryReader内部的所有视图都会缩小以适合其内容,因此您的contentShape矩形在此无济于事。

答案 1 :(得分:0)

由于您始终设置了高度,因此可以简单地删除GeometryReader:

struct ContentRow: View {
    var item: Item
    
    var body: some View {
        VStack {
            ZStack{
                VStack(alignment: .trailing) {
                    Text(item.name)
                        .font(.caption)
                }
            }
            .padding()
            .foregroundColor(Color.primary)
            .frame(width: 120, height: 120)
            .border(Color.primary, width: 2)
            .cornerRadius(5)
            .background(Color.red)
        }
    }
}