简体   繁体   中英

SwiftUI - Not able to search and toggle in a list

I have a list of cars with a toggle button next to each car. There is also a SearchBar at top. Currently, toogle works fine when search bar is empty. When I type something in search bar, it neither filters the list nor toggle maintains its position. How can I maintain toggle position for each car when list is filtered?

For instance, if I select top three cars without search text. Now I start typing in the search bar, top three toggles remain enabled.

在此处输入图像描述

struct Car: Identifiable {
    var id = UUID()
    var name: String
    var selected: Bool = false
}
struct ContentView: View {
    @State var cars = [Car(name: "Subaru WRX", selected: false), Car(name:"Tesla Model 3",selected: false), Car(name:"Porsche 911 sjfnewif ewihf dwehifiw eufhwueif uhewfuwe u",selected: false), Car(name:"Renault Zoe",selected: false), Car(name:"DeLorean",selected: false), Car(name:"Mitsubishi Lancer",selected: false), Car(name:"Audi RS6", selected:false),Car(name:"Subaru WRX",selected: false), Car(name:"Tesla Model 3",selected: false), Car(name:"Porsche 911",selected: false), Car(name:"Renault Zoe",selected: false), Car(name:"DeLorean",selected: false), Car(name:"Mitsubishi Lancer",selected: false), Car(name:"Audi RS6", selected:false),
                Car(name:"Subaru WRX",selected: false), Car(name:"Tesla Model 3",selected: false), Car(name:"Porsche 911",selected: false), Car(name:"Renault Zoe",selected: false), Car(name:"DeLorean",selected: false), Car(name:"Mitsubishi Lancer",selected: false), Car(name:"Audi RS6",selected:false),
        Car(name:"Subaru WRX",selected: false), Car(name:"Tesla Model 3",selected: false), Car(name:"Porsche 911",selected: false), Car(name:"Renault Zoe",selected: false), Car(name:"DeLorean",selected: false), Car(name:"Mitsubishi Lancer",selected: false), Car(name:"Audi RS6", selected:false),
        Car(name:"Subaru WRX",selected: false), Car(name:"Tesla Model 3",selected: false), Car(name:"Porsche 911",selected: false), Car(name:"Renault Zoe",selected: false), Car(name:"DeLorean",selected: false), Car(name:"Mitsubishi Lancer",selected: false), Car(name:"Audi RS6", selected: false)]
    @State var showAlert = false
    @State private var searchText : String = ""
    var body: some View {
        NavigationView{
            VStack {
                ScrollView {
                    VStack (alignment: .leading) {
                        SearchBar(text: $searchText, placeholder: "Car name")
                        Button(action: {
                            self.showAlert = true
                            print("Button tapped!")
                        }) {
                            Text("Browse by category").foregroundColor(Color.black).padding(.leading).font(.system(size: 15))
                        }.alert(isPresented: $showAlert) {
                            Alert(title: Text("Your Score"), message: Text("\(self.searchText)"))
                        }
                        ForEach(self.cars.filter {
                            self.searchText.isEmpty ? true : $0.name.lowercased().contains(self.searchText.lowercased())
                        }.indices, id: \.self) { idx in
                            ZStack (alignment: .leading) {
                                RoundedRectangle(cornerRadius: 5, style: .continuous)
                                    .fill(Color.white).shadow(color:.green, radius: 5).padding(.leading).padding(.trailing)
                                HStack {
                                    VStack (alignment: .leading) {
                                        Text(self.cars[idx].name)
                                        CatalogAvailable()
                                    }.padding(.leading).padding(.trailing)
                                    Toggle(isOn: self.$cars[idx].selected) {
                                        Text("")
                                    }.toggleStyle(CheckboxToggleStyle()).labelsHidden()
                                        .frame(width: 10, height: 10, alignment: .trailing).padding()
                                }.padding().frame(maxWidth: .infinity, alignment: .leading)
                                
                            }.onTapGesture {
                                self.cars[idx].selected.toggle()
                            }
                        }
                    }
                }.navigationBarTitle("Add your cars")
                Button(action: {
                    print("Button tapped!")
                }) {
                    Text("Next")
                }.padding(.bottom)
            }
            
        }
    }
}

You iterate over indices but after filtering they do not correspond to original array, but just ordered indices of filtered array. You have to work with id of cars instead

Here is a sketch of idea:

ForEach(self.cars.filter {
    self.searchText.isEmpty ? true : $0.name.lowercased().contains(self.searchText.lowercased())
}) { car in
   self.row(for: car)
}

...

func row(for car: Car) -> some View {
  let idx = self.cars.firstIndex(of car)!

  return ZStack (alignment: .leading) {
        RoundedRectangle(cornerRadius: 5, style: .continuous)
            .fill(Color.white).shadow(color:.green, radius: 5).padding(.leading).padding(.trailing)
        HStack {
            VStack (alignment: .leading) {
                Text(self.cars[idx].name)
                CatalogAvailable()
            }.padding(.leading).padding(.trailing)
            Toggle(isOn: self.$cars[idx].selected) {
                Text("")
            }.toggleStyle(CheckboxToggleStyle()).labelsHidden()
                .frame(width: 10, height: 10, alignment: .trailing).padding()
        }.padding().frame(maxWidth: .infinity, alignment: .leading)
        
    }.onTapGesture {
        self.cars[idx].selected.toggle()
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM