问题描述
我创建了一个卡片列表,每张卡片都有一个按钮来执行一个操作。 但是当我进行测试时,我注意到我可以点击卡片所在的位置,也可以执行按钮的操作。这是我在 switf 上的第一个应用程序,所以我没有任何经验。 有人可以帮忙吗?
这是项目视图已编辑:
typealias changeStatusAlias = (OrderDTO,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,5)
Text(item.order.user)
.padding(.leading,10)
.padding(.top,10)
.frame(maxWidth: .infinity,alignment: .leading)
Text(item.order.stateName)
.padding(.leading,1)
.frame(maxWidth: .infinity,alignment: .leading)
Text(orderValue!)
.padding(.leading,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,alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
Text("\(item.order.routeTime) min")
.foregroundColor(Color(hue: 1.0,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,alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
.padding(.leading,30)
})
Spacer()
Button(action: {
},label: {
Image("pin_quick_red")
.resizable()
.scaledToFit()
.frame(width: 30,20)
})
Spacer()
Image("info_black")
.resizable()
.scaledToFit()
.frame(width: 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,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() 有这个限制,整个项目都可以点击。 所以我解决了将 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)