SwiftUI中如何利用外接扫码器扫码并模拟onTapGesture触发加入购物车方法
Hey there! Let's get your barcode scanner integration working smoothly so scanning a SKU triggers the same add-to-cart action as tapping a list item. Here's a straightforward solution tailored to your existing code:
The Core Idea
Most external barcode scanners simulate keyboard input—they’ll type the scanned SKU into the active text field and often append a newline character. We can leverage this by listening for changes to your search text, matching the scanned SKU to an item in your list, and then calling your existing AddToCart method.
Modified Implementation
Update your ShowItemList view to add a listener for search text changes. This way, we can capture the scanned SKU and replicate the tap gesture behavior:
struct ShowItemList: View { @StateObject var itemVM = ProductViewListModel() @EnvironmentObject var order: OrderViewModel @State var searchtext = "" var body: some View { SearchItem(searchtext: $searchtext) ItemListHeader() ScrollView { // Your existing ForEach and list item code remains exactly the same here ForEach(itemVM.item.filter({searchtext.isEmpty ? true : $0.sku.contains(searchtext) || $0.label.contains(searchtext)})) { dataPoint in ZStack{ HStack{ Text(dataPoint.label) .frame(width:220, alignment: .leading) .font(Font.system(size: 12, weight: .light)) .padding(.leading,30) Spacer() Text("\(dataPoint.price)") .font(Font.system(size: 12, weight: .light)) Spacer() Text("\(dataPoint.quantity)") .font(Font.system(size: 12, weight: .light)) } .padding(.leading, -20) .padding(.trailing, 20) .padding(.top, 5) .padding(.bottom, 5) }.onTapGesture { self.order.AddToCart(item: dataPoint.product) }.alert(isPresented: $order.isValid) { Alert(title: Text("Not enough stocks remaining"), message: Text("Adjust item or PO item"), dismissButton: .default(Text("OK"))) } Divider() } } .onAppear(perform: itemVM.fetchProduct) .padding() // Add this listener to handle scanned SKUs .onChange(of: searchtext) { updatedText in // Clean up the scanned text (remove newlines/whitespace from scanner input) let cleanedSKU = updatedText.trimmingCharacters(in: .whitespacesAndNewlines) // Skip if the text is empty or product list hasn't loaded yet guard !cleanedSKU.isEmpty, !itemVM.item.isEmpty else { return } // Find the product matching the scanned SKU if let matchedProduct = itemVM.item.first(where: { $0.sku == cleanedSKU }) { // Call the same add-to-cart method as tapping the list item self.order.AddToCart(item: matchedProduct.product) // Clear the search field for the next scan searchtext = "" } } } } // Your existing SearchItem view stays unchanged struct SearchItem: View { @Binding var searchtext: String var body: some View { HStack{ Image(systemName: "magnifyingglass") .padding(.leading, 13) TextField("Search", text: $searchtext) .padding(.leading, -10) .padding() .background(Color.white) } .frame(height: 50, alignment:.center) .border(Color.gray) .cornerRadius(3.0) .padding() } }
Key Details
- Text Cleaning: The
trimmingCharacterscall removes any extra whitespace or newline characters that scanners often add after the SKU. - Product Matching: We use
first(where:)to find the exact SKU match in your product list (assuming SKUs are unique, which they should be for inventory systems). - Reused Logic: We call the exact same
order.AddToCart(item:)method as your tap gesture, so all existing validation (like stock checks) and alerts will work seamlessly. - Search Field Reset: Clearing
searchtextafter a successful scan makes it easy to scan multiple items in a row.
Optional Enhancements
- If your scanner doesn’t auto-focus the search field, add a
.focused($isSearchFieldFocused)modifier to the TextField and setisSearchFieldFocusedtotruewhen the view appears, so the scanner always inputs to the right place. - For faster scanning, add a small debounce if you notice duplicate scans (though most scanners handle this automatically).
内容的提问来源于stack exchange,提问作者Lyndon Abesamis

