import UIKit
class SearchViewController: UIViewController {
// MARK: - Variables
var spotResults: [AttractionItem] = []
// MARK: - UI Components
/// 검색어를 입력할 서치바 생성
let searchBar: UISearchBar = {
let searchBar = UISearchBar()
searchBar.translatesAutoresizingMaskIntoConstraints = false
searchBar.placeholder = "키워드를 입력해주세요"
searchBar.searchBarStyle = .minimal
return searchBar
}()
/// 검색한 결과를 보여줄 테이블뷰 생성
let spotResultsTableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .grouped)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.backgroundColor = .clear
tableView.separatorStyle = .none
tableView.isHidden = true // 초기에는 테이블뷰를 숨깁니다.
return tableView
}()
// MARK: - Initializations
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
searchBar.delegate = self
configureConstraints()
configureNavigationItem()
configureTableView()
configureSearchBarTextField()
keyBoardDown()
}
// MARK: - Layouts
private func configureConstraints() {
view.addSubview(searchBar)
view.addSubview(spotResultsTableView)
NSLayoutConstraint.activate([
// 서치바 레이아웃 설정
searchBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
searchBar.leadingAnchor.constraint(equalTo: view.leadingAnchor),
searchBar.trailingAnchor.constraint(equalTo: view.trailingAnchor),
// 결과를 보여주는 테이블 레이아웃 설정 (서치바 바로 아래)
spotResultsTableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
spotResultsTableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
spotResultsTableView.topAnchor.constraint(equalTo: searchBar.bottomAnchor, constant: 10),
spotResultsTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
// MARK: - Functions
/// 네비게이션 아이템 설정 함수
func configureNavigationItem() {
let titleLabel = UILabel()
titleLabel.text = "Search"
titleLabel.textColor = .label
titleLabel.font = .systemFont(ofSize: 28, weight: .black)
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: titleLabel)
}
/// 검색결과를 보여주는 테이블뷰 관련 설정을 하는 함수
func configureTableView() {
spotResultsTableView.delegate = self
spotResultsTableView.dataSource = self
spotResultsTableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
/// 서치바를 커스텀하여 사용할 수 있도록 하는 함수
func configureSearchBarTextField() {
// UITextField appearance 설정
let searchTextFieldAppearance = UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self])
searchTextFieldAppearance.backgroundColor = UIColor.systemGray5 // 텍스트 필드 배경색
searchTextFieldAppearance.layer.cornerRadius = 18 // 라운드 코너
searchTextFieldAppearance.layer.masksToBounds = true
searchTextFieldAppearance.textColor = .label// 텍스트 색상
searchTextFieldAppearance.font = UIFont.systemFont(ofSize: 16) // 폰트 크기
// 커스텀 아이콘 설정
if let textField = searchBar.value(forKey: "searchField") as? UITextField {
let customIcon = UIImage(systemName: "magnifyingglass")?.withConfiguration(UIImage.SymbolConfiguration(pointSize: 25, weight: .bold))
let iconView = UIImageView(image: customIcon)
iconView.tintColor = .black
iconView.contentMode = .scaleAspectFit // 크기 맞춤 설정
iconView.frame = CGRect(x: 0, y: 0, width: 25, height: 25) // 아이콘 크기 설정
// leftView에 커스텀 아이콘 적용
textField.leftView = iconView
textField.leftViewMode = .always // 텍스트필드의 eftView가 언제 표시될지를 결정하는 속성
}
}
/// 검색어를 갖고 외부API를 통해 데이터를 불러오는 함수
func searchForKeyword(with keyword: String) {
NetworkManager.shared.searchKeywordList(keyword: keyword) { [weak self] results in
switch results {
case .success(let items):
let searchList = items.response.body.items.item
self?.spotResults = searchList
DispatchQueue.main.async {
// 검색 결과가 있으면 테이블 뷰를 표시하고 없으면 숨깁니다.
self?.spotResultsTableView.isHidden = searchList.isEmpty
self?.spotResultsTableView.reloadData()
}
case .failure(let error):
print(error.localizedDescription)
}
}
}
func keyBoardDown() {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
view.addGestureRecognizer(tapGesture)
}
// MARK: - Actions
/// 빈 화면을 터치할 때 호출되는 메서드
@objc func dismissKeyboard() {
view.endEditing(true)
}
}
// MARK: - UISearchBarDelegate
extension SearchViewController: UISearchBarDelegate {
// 사용자가 서치 버트을 눌렀을 때 호출되는 함수
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
guard let query = searchBar.text, !query.isEmpty else {
print("검색어가 비어있습니다.")
return
}
self.searchForKeyword(with: query)
searchBar.resignFirstResponder()
}
// 사용자가 검색어를 변경할 때마다 호출되는 함수
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
// 검색어가 비어있으면 테이블 뷰를 숨김
if searchText.isEmpty {
spotResults = []
spotResultsTableView.isHidden = true
spotResultsTableView.reloadData()
}
}
}
// MARK: - UITableViewDelegate, UITableViewDataSource
extension SearchViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return spotResults.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = spotResults[indexPath.row].title
return cell
}
}
/// 키워드를 가지고 결과를 보여주는 함수
func searchKeywordList(pageNo: String = "1", keyword: String, completion: @escaping (Result<AttractionResponse, Error>) -> Void) {
var components = URLComponents(string: "\(Constants.base_URL)/searchKeyword1")
// 쿼리 아이템 설정
components?.queryItems = [
URLQueryItem(name: "serviceKey", value: Constants.api_key),
URLQueryItem(name: "numOfRows", value: "10"),
URLQueryItem(name: "pageNo", value: pageNo),
URLQueryItem(name: "MobileOS", value: "iOS"),
URLQueryItem(name: "MobileApp", value: "AppTest"),
URLQueryItem(name: "_type", value: "json"),
URLQueryItem(name: "listYN", value: "Y"),
URLQueryItem(name: "arrange", value: "Q"),
URLQueryItem(name: "keyword", value: keyword) // 검색 키워드
]
// 퍼센트 인코딩 후 "+"를 "%2B"로 대체
if let encodedQuery = components?.percentEncodedQuery?.replacingOccurrences(of: "%25", with: "%") {
components?.percentEncodedQuery = encodedQuery
}
// URL 생성
guard let url = components?.url else { return }
let task = URLSession.shared.dataTask(with: URLRequest(url: url)) { data, _, error in
guard let data = data, error == nil else {
print("Network error: \(String(describing: error))")
return completion(.failure(error!))
}
do {
let results = try JSONDecoder().decode(AttractionResponse.self, from: data)
completion(.success(results))
} catch {
print("Decoding error: \(error)")
completion(.failure(error))
}
}
task.resume()
}
- searchBar에 검색어를 입력하면 검색한 결과가 테이블뷰에 보이게 함
- searchBar에 검색어를 지우면 테이블뷰도 빈테이블로 변경됨
'iOS > UIKIT' 카테고리의 다른 글
카테고리별 검색 결과를 5개 보여주는 방법 (0) | 2024.10.29 |
---|---|
검색결과를 카테고리별로 구분하기 (5) | 2024.10.28 |
UISearchBar 사용하기 (0) | 2024.10.26 |
나중에 꼭 해봐야할 "공유" 기능 -> UIActivityViewController (2) | 2024.10.24 |
컬렉션뷰에 있는 이미지를 누르면 전체화면에서 볼수 있는 방법은? (0) | 2024.10.22 |