기존엔 navigationBar.searchController = searchController하는 식으로 직접 넣어서 했는데
검색 시 아무리 설정해줘도 상단 라지타이틀이 보여야하는데 올라가는 점이 맘에 들지 않았다.
그럼.. navigationBar 내부 설정에 searchController와 관련된 일정한 동작이 이미 구현되어있다면..!?
SearchController를 navigationBar 밖으로 빼서 고정하게 된다면 largeTitle에 문제가 없지 않을까!
import UIKit
class MainViewController: UIViewController {
private let mainView = MainView()
private let viewModel = MainViewModel()
private let searchController = UISearchController()
override func viewDidLoad() {
super.viewDidLoad()
configure()
Task {
await fetchData()
}
}
private func fetchData() async {
do {
try await viewModel.fetchData()
await MainActor.run {
mainView.reloadTableView()
}
} catch let error as APIError {
showAlert(message: error.errorMessage)
} catch {
showAlert(message: "데이터 로드에 실패했습니다.")
}
}
private func searchControllerSetting() {
searchController.searchResultsUpdater = self
searchController.searchBar.placeholder = "통화 검색"
searchController.searchBar.searchBarStyle = .minimal
searchController.searchBar.showsCancelButton = false
}
private func navigationControllerSetting() {
navigationController?.navigationBar.prefersLargeTitles = true
navigationController?.navigationBar.topItem?.title = "환율 정보"
}
}
private extension MainViewController {
func configure() {
mainView.configure(dataSource: self, delegate: self)
searchControllerSetting()
navigationControllerSetting()
setHierarchy()
setConstraints()
}
func setHierarchy() {
view.addSubViews(views: searchController.searchBar, mainView)
}
func setConstraints() {
searchController.searchBar.snp.makeConstraints { make in
make.top.directionalHorizontalEdges.equalTo(view.safeAreaLayoutGuide)
}
mainView.snp.makeConstraints { make in
make.top.equalTo(searchController.searchBar.snp.bottom)
make.directionalHorizontalEdges.bottom.equalTo(view.safeAreaLayoutGuide)
}
}
}
extension MainViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.filteredItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: ExchangeRateCell.identifier) as? ExchangeRateCell else {
return UITableViewCell()
}
let currencyItem = viewModel.filteredItems[indexPath.row]
cell.configure(with: currencyItem)
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
}
extension MainViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
guard let searchText = searchController.searchBar.text else { return }
if !searchText.isEmpty {
viewModel.filterCurrencyItems(by: searchText)
mainView.reloadTableView()
} else {
viewModel.resetFilteredItems()
mainView.reloadTableView()
}
}
}
결과는
저 텍스트필드를 탭하면 상단으로 올라가려는게 더 극단적으로 변했다...
그래서 그냥 searchController의 편의성을 포기하고 searchBar 자체를 View 자체에 따로 고정해서 관리하기로 했다.
import UIKit
import SnapKit
class MainView: UIView {
private let searchBar: UISearchBar = {
let searchBar = UISearchBar()
searchBar.placeholder = "통화 검색"
searchBar.backgroundImage = UIImage()
searchBar.searchBarStyle = .default
searchBar.showsCancelButton = false
return searchBar
}()
private let tableView: UITableView = {
let tableView = UITableView()
tableView.backgroundColor = .systemBackground
tableView.register(ExchangeRateCell.self, forCellReuseIdentifier: ExchangeRateCell.identifier)
tableView.allowsMultipleSelection = false
return tableView
}()
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
@available(*, unavailable, message: "storyboard is not supported.")
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented.")
}
func configureTableView(dataSource: UITableViewDataSource, delegate: UITableViewDelegate) {
tableView.dataSource = dataSource
tableView.delegate = delegate
}
func configureSearchBar(delegate: UISearchBarDelegate) {
searchBar.delegate = delegate
}
func reloadTableView() {
tableView.reloadData()
}
func scrollToTop() {
let indexPath = IndexPath(row: 0, section: 0)
self.tableView.scrollToRow(at: indexPath, at: .top, animated: false)
}
}
private extension MainView {
func configure() {
setLayout()
setHierarchy()
setConstraints()
}
func setLayout() {
backgroundColor = .systemBackground
}
func setHierarchy() {
addSubViews(views: searchBar, tableView)
}
func setConstraints() {
searchBar.snp.makeConstraints { make in
make.top.directionalHorizontalEdges.equalTo(safeAreaLayoutGuide)
}
tableView.snp.makeConstraints { make in
make.top.equalTo(searchBar.snp.bottom)
make.directionalHorizontalEdges.bottom.equalTo(safeAreaLayoutGuide)
}
}
}
extension MainViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if !searchText.isEmpty {
viewModel.filterCurrencyItems(by: searchText)
mainView.reloadTableView()
} else {
viewModel.resetFilteredItems()
mainView.reloadTableView()
}
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
}
}
SearchController의 경우 검색어에 반응해 업데이트하는 로직에 편의성이 이미 제공되고 있었지만 searchBar의 경우 직접 구현해줘야했다. 다만 이미 textField의 메서드를 쓸 수 있어 textDidChange에 트리거를 걸어 해당 로직을 수행하도록 했다.
요런식으로 UISearchBar만 레이아웃 고정 후 delegate 관련 설정들을 해주어 고정하도록 했다.
UISearchController의 경우 복잡한 검색에 유용한 기능들이 많아서 쓰기 좋다고는 하나 이런 요구사항을 충족해야할 경우 UISearchBar로 만들어 모든 요구사항을 별도로 구현해줘야하는 불편함이 있을 것 같은데 아직 모르는 부분이 있을지도 모를지도...!
기본 제공되는 기능과 요구사항이 상이한 부분이 있다면 꽤 골치 아파질 것 같다.
'iOS > Swift' 카테고리의 다른 글
[WIL / 25.05.06] 8~9주차 회고 및 To-do (2) | 2025.05.06 |
---|---|
[TIL / 25.04.17] URLSession으로.. 네트워크 통신을 어떻게 하는지.. 보여줄래요 (2) | 2025.04.17 |
[TIL / 25.04.11] UICollectionView Compositional Layout 1 (0) | 2025.04.11 |
[TIL / 25.03.31] 앨범에서 사진 고르고 잘라서 쓸 수 있도록! (feat. PHPickerViewController, TOCropViewController) (0) | 2025.03.31 |
[TIL / 25.03.28] 과제 5, 스택뷰가 보이지 않는 문제 해결 (2) | 2025.03.28 |