单击列表项上的按钮与整个项重叠

Posted

技术标签:

【中文标题】单击列表项上的按钮与整个项重叠【英文标题】:The Click of a button on item's of List is overlapping the entire Item 【发布时间】:2021-05-29 18:22:51 【问题描述】:

我创建了一张卡片列表,每张卡片都有一个执行操作的按钮。 但是当我在测试时,我注意到我可以点击卡片的位置也可以执行按钮的操作。这是我在 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!)
        
    

【问题讨论】:

包括minimal reproducible example 【参考方案1】:

看起来 List() 有这个限制,整个项目都是可点击的。 所以我解决了将 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)

【讨论】:

以上是关于单击列表项上的按钮与整个项重叠的主要内容,如果未能解决你的问题,请参考以下文章

由 UITableView 制成的下拉按钮不重叠按钮

如何知道单击按钮的列表项的索引

导航栏标题视图与左栏按钮项重叠

悬停列表项上的引导导航栏删除类活动,鼠标移出返回类活动

如何处理Swift 4中的按钮重叠?

屏幕旋转后Android片段重叠