有人可以告诉我为什么这个选择不起作用吗?如果我单击其中一行,则ForEach什么也不会发生:/
@FetchRequest(fetchRequest: ContentView.manufacturerByName)
var manufacturers:FetchedResults<Manufacturer>
@State private var selection: Manufacturer?
Section("Manufacturer") {
List(selection: $selection) {
ForEach(manufacturers, id:\.self) { manufacturer in
Text(manufacturer.name ?? "--")
}
.onDelete { rows in
for row in rows {
let manufacturer = manufacturers[row]
storageProvider.deleteManufacturer(manufacturer)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
该.onDelete方法效果很好。
我想要实现的是,当单击制造商行时,
我知道 AppStore 不允许使用烟草的应用程序。这只是一个学习应用程序。
MyApp.swift
@main
struct MyApp: App {
let storageProvider = StorageProvider.standard
var body: some Scene {
WindowGroup {
ContentView(storageProvider: storageProvider)
.environment(\.managedObjectContext, storageProvider.persistentContainer.viewContext)
}
}
}
Run Code Online (Sandbox Code Playgroud)
ContentView.swift
import SwiftUI
import CodeScanner
struct ContentView: View {
@Environment(\.dismiss) var dismiss
let storageProvider: StorageProvider
// Tobacco
@State var tobaccoName: String = ""
@State var tobaccoNr: String? = nil
@State var ean: String? = nil
// EAN
@State private var isPresentingScanner = false
@State private var scannedCode: String?
// Manufacturers
@FetchRequest(fetchRequest: ContentView.manufacturerByName)
var manufacturers: FetchedResults<Manufacturer>
@StateObject var searchText = SearchText()
@State private var selection: Manufacturer?
var body: some View {
Form {
Section("Tobacco Details") {
TextField("Name", text: $tobaccoName)
TextField("Number (e.g. #017)", text: $tobaccoNr ?? "")
.keyboardType(.decimalPad)
HStack {
TextField("ean", text: $ean ?? "")
.keyboardType(.numberPad)
Button {
isPresentingScanner.toggle()
} label: {
Image(systemName: "camera")
}
}
}
Text(selection?.name ?? "no selection") // <-- here
Button {
storageProvider.saveManufacturer(named: "Test")
} label: {
Text("create manufacturer")
}
Section("Manufacturer") {
List(selection: $selection) {
ForEach(manufacturers, id:\.self) { manufacturer in
// -- here, use a Label
Label(manufacturer.name ?? "--",
systemImage: selection == manufacturer ? "checkmark" : "circle")
}
.onDelete { rows in
for row in rows {
let manufacturer = manufacturers[row]
// storageProvider.deleteManufacturer(manufacturer)
}
}
}
}
}
.navigationTitle("add Tobacco")
.navigationBarTitleDisplayMode(.inline)
// MARK: - EAN-Scan Sheet
.sheet(isPresented: $isPresentingScanner) {
CodeScannerView(codeTypes: [.ean13], showViewfinder: true) { response in
switch response {
case .success(let result): do {
ean = result.string
isPresentingScanner = false
}
case .failure(let error):
print(error.localizedDescription)
}
}
.presentationDetents([.medium])
}
// MARK: - Bottom Button
.safeAreaInset(edge: .bottom) {
VStack {
Button {
if selection == nil {
print("no manufacturer")
} else {
storageProvider.saveTabacco(
named: tobaccoName,
number: tobaccoNr,
ean: ean,
manufacturer: selection
)
dismiss()
}
} label: {
Text("save Tobacco")
.font(.callout)
.frame(maxWidth: .infinity, minHeight: 44)
}
.buttonStyle(.borderedProminent)
.contentTransition(.identity)
}
.frame(maxWidth: .infinity)
.padding([.horizontal, .top])
.background(.ultraThinMaterial)
}
// MARK: - Manufacturer Search-Filter
.onReceive(searchText.$debounced) { query in
/// don't filter when searchbar is empty
guard !query.isEmpty else {
manufacturers.nsPredicate = nil
return
}
/// set filter when someone searches
manufacturers.nsPredicate = NSPredicate(format: "%K CONTAINS[cd] %@", argumentArray: [#keyPath(Manufacturer.name), query])
}
}
}
func ??<T>(lhs: Binding<Optional<T>>, rhs: T) -> Binding<T> {
Binding(
get: { lhs.wrappedValue ?? rhs },
set: { lhs.wrappedValue = $0 }
)
}
Run Code Online (Sandbox Code Playgroud)
StorageProvider.swift
public class StorageProvider {
public static var standard = StorageProvider()
public let persistentContainer: NSPersistentContainer
public init() {
persistentContainer = NSPersistentContainer(name: "DataModel")
persistentContainer.loadPersistentStores(completionHandler: { description, error in
if let error = error {
fatalError("Core Data store failed to load with error: \(error)")
}
})
}
}
// MARK: - Functions to call from the Views
public extension StorageProvider {
func saveTabacco(named name: String, number: String?, ean: String?, manufacturer: Manufacturer?) {
let tabacco = Tabacco(context: persistentContainer.viewContext)
tabacco.name = name
tabacco.number = number
tabacco.ean = ean
tabacco.manufacturer = manufacturer
tabacco.creationDate = Date.now
do {
try persistentContainer.viewContext.save()
print("Tabacco saved succesfully")
} catch {
persistentContainer.viewContext.rollback()
print("Failed to save Tabacco: \(error)")
}
}
func saveManufacturer(named name: String) {
let manufacturer = Manufacturer(context: persistentContainer.viewContext)
manufacturer.name = name
do {
try persistentContainer.viewContext.save()
print("Manufacturer saved succesfully")
} catch {
persistentContainer.viewContext.rollback()
print("Failed to save Manufacturer: \(error)")
}
}
func getAllTabaccos() -> [Tabacco] {
let fetchRequest: NSFetchRequest<Tabacco> = Tabacco.fetchRequest()
do {
return try persistentContainer.viewContext.fetch(fetchRequest)
} catch {
print("Failed to fetch tabacco: \(error)")
return []
}
}
func deleteTabacco(_ tabacco: Tabacco) {
persistentContainer.viewContext.delete(tabacco)
do {
try persistentContainer.viewContext.save()
} catch {
persistentContainer.viewContext.rollback()
print("Failed to save context: \(error)")
}
}
func deleteManufacturer(_ manufacturer: Manufacturer) {
persistentContainer.viewContext.delete(manufacturer)
do {
try persistentContainer.viewContext.save()
} catch {
persistentContainer.viewContext.rollback()
print("Failed to save context: \(error)")
}
}
func updateTabacco(_ tabacco: Tabacco) {
do {
try persistentContainer.viewContext.save()
} catch {
persistentContainer.viewContext.rollback()
print("Failed to save context: \(error)")
}
}
}
// MARK: - FetchRequest
extension ContentView {
static var tabaccosByName: NSFetchRequest<Tabacco> {
/// create Request
let request: NSFetchRequest<Tabacco> = Tabacco.fetchRequest()
/// sortDescriptor
request.sortDescriptors = [NSSortDescriptor(keyPath: \Tabacco.name, ascending: true)]
return request
}
static var manufacturerByName: NSFetchRequest<Manufacturer> {
/// create Request
let request: NSFetchRequest<Manufacturer> = Manufacturer.fetchRequest()
/// sortDescriptor
request.sortDescriptors = [NSSortDescriptor(keyPath: \Manufacturer.name, ascending: true)]
return request
}
}
Run Code Online (Sandbox Code Playgroud)
Section("Manufacturer") {
List() {
TextField("search for manufacturer", text: $searchText.text)
if manufacturers.isEmpty {
if searchText.debounced != "" {
NavigationLink(destination: CreateManuView(storageProvider: storageProvider, manuName: searchText.text)) {
Label("add **\(searchText.text)**", systemImage: "plus")
.tint(.accentColor)
}
} else {
Text("search for a manufacturer to add")
.foregroundColor(.gray)
}
}
ForEach(manufacturers) { manufacturer in
Button(action: {
selection = manufacturer
}, label: {
HStack {
Text(manufacturer.name ?? "--")
.tint(.primary)
Spacer()
if manufacturer == selection {
Image(systemName: "checkmark")
}
}
})
}
.onDelete { rows in
for row in rows {
let manufacturer = manufacturers[row]
storageProvider.deleteManufacturer(manufacturer)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
下面是一个示例代码,显示了checkmark选择列表中的一行时的情况,并显示selection变量包含List(selection: $selection).
struct ContentView: View {
// for testing
// @State var manufacturers = [Manufacturer(name: "one"), Manufacturer(name: "two"), Manufacturer(name: "three")]
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Manufacturer.name, ascending: true)],
animation: .default)
private var manufacturers: FetchedResults<Manufacturer>
@State private var selection: Manufacturer?
var body: some View{
Text(selection?.name ?? "no selection") // <-- here
Section("Manufacturer") {
List(selection: $selection) {
ForEach(manufacturers) { manufacturer in
// -- here, use a Label
Label(manufacturer.name ?? "--",
systemImage: selection == manufacturer ? "checkmark" : "circle")
}
.onDelete { rows in
for row in rows {
let manufacturer = manufacturers[row]
// storageProvider.deleteManufacturer(manufacturer)
}
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2094 次 |
| 最近记录: |