Reputation: 37
struct Test: View {
@ObservedObject var datas2 = ReadData2()
@State var selectedIndex2 = 0
var body: some View {
VStack{
List{
HStack{
Text("From")
.foregroundColor(Color("Color"))
.fontWeight(.bold)
.font(.system(size: 20))
.padding(.leading, 10.0)
.frame(width: nil, height: nil, alignment: .leading)
Picker(selection: $selectedIndex2, label: Text("")) {
ForEach(0 ..< datas2.cities.count, id: \.self) {
Text(datas2.cities[$0].name)
}
}.foregroundColor(Color("Color"))
.padding(.trailing)
}
}
}
}
struct City: Codable, Identifiable {
enum CodingKeys: CodingKey {
case name
}
var id = UUID()
var name: String
}
class ReadData2: ObservableObject {
@Published var cities = [City]()
init(){
loadData()
}
func loadData() {
guard let url = Bundle.main.url(forResource: "cities", withExtension: "json")
else {
print("Json file not found")
return
}
let data = try? Data(contentsOf: url)
let cities = try? JSONDecoder().decode([City].self, from: data!)
self.cities = cities!
}
}
and I have a json file called cities that is like this :
{
"country": "AD",
"name": "Sant Julià de Lòria",
"lat": "42.46372",
"lng": "1.49129"
},
{
"country": "AD",
"name": "Pas de la Casa",
"lat": "42.54277",
"lng": "1.73361"
},
{
"country": "AD",
"name": "Ordino",
"lat": "42.55623",
"lng": "1.53319"
},
{
"country": "AD",
"name": "les Escaldes",
"lat": "42.50729",
"lng": "1.53414"
},
{
"country": "AD",
"name": "la Massana",
"lat": "42.54499",
"lng": "1.51483"
},
My problem is that cites are too much data, and once I press the picker it takes a long time to read data and post data inside the picker, is there a better way for making it faster ?
and I am trying to make it searchable throught a search text taking the first letter of the city and it is not working !
I hope you can help me !
Upvotes: 0
Views: 116
Reputation: 36304
With very large number of items, I would suggest using a List
or a LazyVStack
that are optimised for that, instead of a Picker
.
Something like the following example code.
Note, you will have to adjust the UI for your purpose.
struct ContentView: View {
var body: some View {
Test()
}
}
struct Test: View {
@StateObject var datas2 = ReadData2()
@State var selectedCity: City?
@State private var searchQuery: String = ""
var body: some View {
VStack (spacing: 20) {
TextField("city search", text: $searchQuery).padding(5)
.overlay(RoundedRectangle(cornerRadius: 15).stroke(Color.blue, lineWidth: 1))
.foregroundColor(.blue)
.frame(width: 160)
.padding(.top, 20.0)
HStack {
Text("From")
.fontWeight(.bold)
.font(.system(size: 20))
.padding(.leading, 10.0)
Spacer()
ScrollView {
LazyVStack {
ForEach(datas2.cities.filter{searchFor($0.name)}.sorted(by: { $0.name < $1.name })) { city in
Text(city.name).foregroundColor(selectedCity == city ? .red : .blue)
.onTapGesture {
selectedCity = city
}
}
}
}.frame(width: 222, height: 111)
}
Spacer()
}
}
private func searchFor(_ txt: String) -> Bool {
return (txt.lowercased(with: .current).hasPrefix(searchQuery.trimmingCharacters(in: .whitespacesAndNewlines).lowercased(with: .current)) || searchQuery.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
}
}
struct City: Codable, Identifiable, Hashable {
enum CodingKeys: CodingKey {
case name
}
var id = UUID()
var name: String
}
class ReadData2: ObservableObject {
@Published var cities = [City]()
init() {
loadData()
}
func loadData() {
if let url = Bundle.main.url(forResource: "cities", withExtension: "json") {
do {
let data = try Data(contentsOf: url)
cities = try JSONDecoder().decode([City].self, from: data)
} catch {
print(" error:\(error)")
}
}
}
}
Upvotes: 1