Created
August 31, 2022 19:49
-
-
Save akardas16/5ee5c7c767a9cc46fe3e657d9d78f408 to your computer and use it in GitHub Desktop.
SearchBar example with suggestions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// SearchBarView.swift | |
// CombineApp | |
// | |
// Created by Abdullah Kardas on 31.08.2022. | |
// | |
import SwiftUI | |
import Combine | |
struct CityModel:Identifiable { | |
let id: UUID = UUID() | |
let name:String | |
let degree:Double | |
} | |
class SearchBarViewModel:ObservableObject { | |
@Published var text:String = "" | |
@Published var cityList = [CityModel(name: "New York", degree: 25),CityModel(name: "Washington", degree: 20.4),CityModel(name: "New Jersey", degree: 14),CityModel(name: "New Mexico", degree: 25),CityModel(name: "Chicago", degree: 25),CityModel(name: "Boston", degree: 17),CityModel(name: "Los Angeles", degree: 8)] | |
@Published var fileteredList:[CityModel] = [] | |
var cancallable = Set<AnyCancellable>() | |
init(){ | |
$text.map { txt in | |
var model:[CityModel] = [] | |
for city in self.cityList where city.name.lowercased().contains(txt.lowercased()) { | |
model.append(city) | |
} | |
return model | |
}.sink { newModel in | |
self.fileteredList = newModel | |
}.store(in: &cancallable) | |
} | |
} | |
struct SearchBarView: View { | |
@State var isKeyboardPresented = false | |
@StateObject var vm = SearchBarViewModel() | |
@State var city:CityModel = CityModel(name: "Los Angeles", degree: 0) | |
var body: some View { | |
ZStack(alignment:.top) { | |
VStack{ | |
//Search | |
HStack(spacing:0) { | |
HStack(spacing:8){ | |
Image(systemName: "magnifyingglass") | |
TextField("Search any city...", text: $vm.text).autocorrectionDisabled(true) | |
Image(systemName: "xmark.circle.fill").foregroundColor(.gray).opacity(vm.text.count > 0 ? 1:0) | |
.onTapGesture { | |
vm.text = "" | |
} | |
}.padding(.horizontal).padding(.vertical,12).background ( | |
Capsule(style: .circular).fill(.gray.opacity(0.3)) | |
).padding(.horizontal,6) | |
if isKeyboardPresented { | |
Text("Cancel").foregroundColor(.blue) | |
.padding(.trailing,6) | |
.onTapGesture { | |
vm.text = "" | |
hideKeyboard() | |
isKeyboardPresented = false | |
} | |
} | |
}.onReceive(keyboardPublisher) { value in | |
isKeyboardPresented = value | |
} | |
//Search List | |
if vm.text.count > 0 { | |
List { | |
ForEach(vm.fileteredList) { city in | |
Text(city.name).onTapGesture { | |
self.city = city | |
vm.text = "" | |
hideKeyboard() | |
isKeyboardPresented = false | |
} | |
} | |
}.listStyle(.plain) | |
} | |
Spacer() | |
Text(city.name).font(.largeTitle).bold() | |
Text("\(Int(city.degree)) °C").font(.largeTitle) | |
Spacer() | |
} | |
} | |
} | |
} | |
struct SearchBarView_Previews: PreviewProvider { | |
static var previews: some View { | |
SearchBarView() | |
} | |
} | |
extension View { | |
func hideKeyboard() { | |
let resign = #selector(UIResponder.resignFirstResponder) | |
UIApplication.shared.sendAction(resign, to: nil, from: nil, for: nil) | |
} | |
} | |
extension View {//Listen keyboard changes | |
var keyboardPublisher: AnyPublisher<Bool, Never> { | |
Publishers | |
.Merge( | |
NotificationCenter | |
.default | |
.publisher(for: UIResponder.keyboardWillShowNotification) | |
.map { _ in true }, | |
NotificationCenter | |
.default | |
.publisher(for: UIResponder.keyboardWillHideNotification) | |
.map { _ in false }) | |
.debounce(for: .seconds(0.1), scheduler: RunLoop.main) | |
.eraseToAnyPublisher() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment