单击列表项上的按钮与整个项重叠
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)
【讨论】:
以上是关于单击列表项上的按钮与整个项重叠的主要内容,如果未能解决你的问题,请参考以下文章