Swiftui 单击项目';列表的个数与整个项目重叠

Swiftui 单击项目';列表的个数与整个项目重叠,swiftui,swiftui-list,Swiftui,Swiftui List,我创建了一个卡片列表,每个卡片上都有一个执行操作的按钮。 但当我在测试时,我注意到我可以点击卡片的位置,按钮的动作也会被执行。这是我在switf上的第一个应用程序,所以我没有任何使用经验。 有人能帮忙吗 这是已编辑的项目视图: typealias changeStatusAlias = (OrderDTO, String, String, String?) -> Void struct OrderItem: Identifiable { let id = UUID() l

我创建了一个卡片列表,每个卡片上都有一个执行操作的按钮。 但当我在测试时,我注意到我可以点击卡片的位置,按钮的动作也会被执行。这是我在switf上的第一个应用程序,所以我没有任何使用经验。 有人能帮忙吗

这是已编辑的项目视图:

typealias changeStatusAlias = (OrderDTO, String, String, String?) -> Void

struct OrderItem: Identifiable {
    let id = UUID()
    let order: OrderDTO
}
struct ItemOrderRiderView: View {
    
    private let item: OrderItem
    @State private var showMethodPicker = false
    private let changeState: changeStatusAlias
    private let showDialogPayment: (OrderDTO)-> Void
    private let orderValue: String?
    @ObservedObject var locationManager = LocationManager()

    init(item: OrderItem, changeState: @escaping changeStatusAlias, showDialogPayment: @escaping (OrderDTO)-> Void) {
        let formatter = NumberFormatter()
        self.item = item
            formatter.numberStyle = NumberFormatter.Style.currencyAccounting
            formatter.locale = Locale(identifier: "DE")
            formatter.currencyCode = "eur"
        self.changeState = changeState
        self.showDialogPayment = showDialogPayment
        orderValue = formatter.string(from: NSNumber(value: item.order.value))
    }
    
    var body: some View {
        ZStack {
            
            VStack {
                HStack{
                    Text(item.order.orderNumber)
                        .fontWeight(.bold)
                        .padding(.leading, /*@START_MENU_TOKEN@*/10/*@END_MENU_TOKEN@*/)
                    
                    Spacer()
                    Text(item.order.subStateName)
                        .padding(.trailing,10)
                }.padding(.top, 5)
                
                HStack{
                    Text(item.order.commercialName)
                        .fontWeight(.bold)
                        .padding(.leading, /*@START_MENU_TOKEN@*/10/*@END_MENU_TOKEN@*/)
                    
                    Spacer()
                    Text(item.order.deliveryHour)
                        .padding(.trailing,10)
                }.padding(.top, 5)
                
                Text(item.order.user)
                    .padding(.leading, 10)
                    .padding(.top, 10)
                    .frame(maxWidth: .infinity,alignment: .leading)
                
                Text(item.order.stateName)
                    .padding(.leading, 10)
                    .padding(.top, 1)
                    .frame(maxWidth: .infinity,alignment: .leading)
                
                Text(orderValue!)
                    .padding(.leading, 10)
                    .padding(.top, 1)
                    .frame(maxWidth: .infinity,alignment: .leading)
                
                HStack {
                    Image("pin_grey")
                        .resizable()
                        .scaledToFit()
                        .frame(width: 30, height: 30, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
                    Text("\(item.order.routeDistance) km")
                        .foregroundColor(Color(hue: 1.0, saturation: 0.045, brightness: 0.397))
                        .font(.system(size: 14))
                        
                        
                    
                    Spacer()
                    
                    Image("watch_grey")
                        .resizable()
                        .scaledToFit()
                        .frame(width: 30, height: 30, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
                    Text("\(item.order.routeTime) min")
                        .foregroundColor(Color(hue: 1.0, saturation: 0.045, brightness: 0.397))
                        .font(.system(size: 14))
                    
                    Button(action: {
                        self.locationManager.locationString = item.order.completeAddress ?? ""
                        self.locationManager.openMapWithAddress()
                    }, label: {
                        Image("map_loc_red")
                            .resizable()
                            .scaledToFit()
                            .frame(width: 30, height: 30, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
                            .padding(.leading, 30)
                    })
                
                    Spacer()
                    
                    Button(action: {
                        
                    }, label: {
                        Image("pin_quick_red")
                            .resizable()
                            .scaledToFit()
                            .frame(width: 30, height: 30, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
                            .padding(.leading, 20)
                    })
                    
                    Spacer()
                    
                    Image("info_black")
                        .resizable()
                        .scaledToFit()
                        .frame(width: 30, height: 30, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
                        .padding(.leading, 20)
                }.padding(.bottom, 10)
                
                Button(
                    action: {
                        
                    switch item.order.riderActions.getRequestValueState(){
                    case "delivered":
                        if(item.order.orderState == "quickdelivery_cash") {
                            showDialogPayment(item.order)
                        } else {
                            changeState(
                                item.order,
                                item.order.riderActions.getRequestValueState(),
                                SubStateAction.Companion().SUB_STATE_FIELD,
                                nil
                            )
                        }
                        break
                    default:
                        changeState(
                            item.order,
                            item.order.riderActions.getRequestValueState(),
                            SubStateAction.Companion().SUB_STATE_FIELD,
                            nil
                        )
                        break
                    }
                }) {
                    Text(item.order.riderActions.getTitle().localized())
                }
                .frame(width: 300, height: 40, alignment: .bottom)
                    
            }.cornerRadius(10)
            .overlay(
                RoundedRectangle(cornerRadius: 10)
                    .stroke(Color(.sRGB, red: 150/255, green: 150/255, blue: 150/255, opacity: 0.1), lineWidth: 1)
            )
            .padding([.top, .horizontal])
            .alert(isPresented: $locationManager.invalid) {
                Alert(title: Text("Important message"), message: Text("Enter a valid address"), dismissButton: .default(Text("OK"), action:{
                                    locationManager.invalid = false
                                    locationManager.locationString = ""
                                }))
                            }
        }
    }
}

struct ItemOrderRiderView_Previews: PreviewProvider {
    static var previews: some View {
        ItemOrderRiderView(
            item: OrderItem(order: mockedOrder),
            changeState: {(mock1,mock2,mock3,mock4) in},
            showDialogPayment: {mock1 in}
        )
            .previewLayout(.fixed(width: 400, height: 400))
    }
}


private let mockedOrder = OrderDTO(
    id: 0001,
    orderNumber: "0001",
    user: "Teste Da Silva",
    kitchenStateName: "ready",
    stateName: "quickdelivery cash",
    subStateName: "in progress",
    deliveryHour: "10:00 - 11:55",
    value: 100,
    type: LoginLabel.Companion().loginButton,
    action: [ResourcesStringDesc](),
    commercialName: "Restaurante teste",
    riderActions: SubStateAction.delivered,
    routeDistance: "100",
    routeTime: "5",
    completeAddress: "rua teste 12",
    googleAddress: "rua teste 12",
    userPhone: "999999999",
    restaurantLocation: Localization(latitude:0,longitude:0),
    riderId: 2312,
    orderState: "quickdelivery_cash",
    deliveryLocation: Localization(latitude: 0, longitude: 0),
    deliveryStateString: "delivery_in_progress",
    commercialPremiseId: 12,
    riderName: "Joao da Silva"
    )
更新: 我执行了其他按钮操作,我也有同样的问题,现在当我点击卡片时,它会执行所有按钮点击操作,因此当我添加一个新按钮时,它也会在我点击卡片时执行

以下是我如何实施列表:

struct DeliveryManagerView: View {
    @ObservedObject private var viewModel: OrderViewModel
    @ObservedObject var profileViewModel: ProfileViewModel
    init(repository: OrderRepository, profileViewModel: ProfileViewModel) {
        self.viewModel = OrderViewModel(repository: repository)
        self.profileViewModel = profileViewModel
    }
    
    let timer = Timer.publish(every: 30, on: .main, in: .common).autoconnect()
    @State private var showPaymentAlert = false

    @State private var order:OrderDTO? = nil
    
    var body: some View {
        
        GeometryReader { proxy in
            ZStack(alignment: .bottom) {
                List(viewModel.ordersItems) { item in
                    ItemOrderRiderView(
                        item: item,
                        changeState: { (order, request, stateField, paymentMethod) in
                                        viewModel.changeOrderState(
                                            orderDTO: order,
                                            request: request,
                                            stateField: stateField,
                                                paymentMethod: paymentMethod
                                                )
                                        },
                        showDialogPayment: {order in
                            self.order = order
                            self.showPaymentAlert = true
                        }
                    )
                }.onAppear(perform: {
                    manageConfigRequests()
                })
                .padding(.bottom, proxy.safeAreaInsets.top)
                
                if(viewModel.loading){
                    ActivityIndicator()
                        .frame(width: 50, height: 50, alignment: .center)
                        .foregroundColor(.orange)
                }
            }.padding(.bottom, proxy.safeAreaInsets.top)
            .customDialog(isShowing: $showPaymentAlert, dialogContent: {
                PaymentMethodAlert { method in
                                    viewModel.changeOrderState(
                                        orderDTO: self.order!,
                                        request: self.order!.riderActions.getRequestValueState(),
                                        stateField: SubStateAction.Companion().SUB_STATE_FIELD,
                                        paymentMethod: method
                                    )
                    self.showPaymentAlert = false
                }
            })
        }.onReceive(timer, perform: { _ in
            viewModel.getOrders(profile: profileViewModel.defaultProfile!)
        })
    }
    
    
    private func manageConfigRequests() {
        if(profileViewModel.defaultProfile != nil) {
            viewModel.getOrders(profile: profileViewModel.defaultProfile!)
        } else {
            profileViewModel.getProfile()
        }
        if(viewModel.changedState) {
            viewModel.getOrders(profile: profileViewModel.defaultProfile!)
        }
    }
}
看起来List()有此限制,整个项目都可以单击。 所以我解决了将列表更改为ScrollView()并使用ForEach()的问题:

包括
 ScrollView {
                    ForEach(viewModel.ordersItems, id: \.self) {
                        item in
                        ItemOrderRiderView(
                            item: item,
                            changeState: { (order, request, stateField, paymentMethod) in
                                viewModel.changeOrderState(
                                    orderDTO: order,
                                    request: request,
                                    stateField: stateField,
                                    paymentMethod: paymentMethod
                                )
                            },
                            showDialogPayment: {order in
                                self.order = order
                                self.showPaymentAlert = true
                            }
                        )
                    }
                }.onAppear(perform: {
                    manageConfigRequests()
                })
                .padding(.bottom, proxy.safeAreaInsets.top)