UISearchController

2024. 10. 6. 16:15·iOS/UIKit
반응형

 

검색 기능은 대부분 서비스에 필수적으로 있는 기능이다.

다양한 스타일로 커스텀이 많이 되어있고 내가 참여하고 있는 왁타버스 뮤직팀의 검색 기능 역시
커스텀하여 사용했다.

 

처음부터 커스텀을 통해 개발하여 기본적인 기능으로는 만들어볼 기회가 없었다.

이번 시간은 애플이 자체적으로 만들어 놓은 UISearchController 기능을 통해 같은 기능을 구현해보자.

 

실제 서비스

1. 왁타버스 뮤직

 

왁타버스 뮤직 앱

세 화면은 앞서 설명한 왁타버스 뮤직앱의 검색화면이다.

  • 검색 전 - 추천 컨텐츠
  • 검색 중 - 최근 검색어
  • 검색 후 - 검색 결과

한번 애플 앱도 살펴보자.

 

2.  앱 스토어

 

앱스토어

왁타버스 뮤직앱과 정확히 일치하는 3단 구성이다.
즉, 애플에서도 이 구성을 구현할 수 있게 만들어놨다는 것

이제는 간단하게 만들어보자.


구현

내용을 간단히 살펴보  Search Bar와 함께 검색 결과를 인터렉션을 통해 자연스럽게 보여주도록 관리해주는
뷰 컨트롤러라고 한다.

 

구조


Root 생성 및 등록 

생성 할 때 보면 searchResultController를 옵셔널로 주입받는다.

너무나 간단하게 추측할 수 있다. 검색 결과를 보여주는 화면인 것 같다.

옵셔널인 것을 보니 안 넣어줘도 되지만 우리의 구성요소에는 필요해보이니 넣는 방향으로 해보자.

우리는 검색 결과 화면을 ResultVC라고 하자.

 

final class RootViewController: UIViewController {

...
    private var resultVC: SearchResultViewController = SearchResultViewController()
    
    private lazy var searchController: UISearchController = {
       let controller = UISearchController(searchResultsController:  resultVC) // 검색 결과 화면 등록과 함께 생성
        controller.searchBar.placeholder = "상태,담당자,레이블..." // 플레이스 홀더
        controller.searchResultsUpdater = resultVC // 검색 결과에 대한 업데이터 등록
        controller.delegate = self // 서치 컨트롤러 델리게이트 등록
        controller.searchBar.delegate = self // 검색바 델리게이트 등록 
        return controller
    }()
     
     override func viewDidLoad() {
     // 네비게이션 아이템에 등록 이렇게해야 자연스러운 인터렉션이 자동으로 동작한다.
     	navigationItem.searchController = searchController 
    
     }
 }
 
 extension RootViewController : UISearchControllerDelegate , UISearchBarDelegate {
 
 	// UISearchControllerDelegate 컨트롤러까지 포함한 전체적인 델리게이트 
    func willPresentSearchController(_ searchController: UISearchController) {
    // 검색창을 클릭했을 때 호출됨 
        searchController.showsSearchResultsController = true // 클릭 되자마자 호출되게 강제
        print("clicked")
    }
    
    
    // UISearchBarDelegate 오직 서치bar 관련 
    func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { 
        //검색 취소 클릭 시 호출 
    }
    
    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
    	// 검색 버튼 클릭 시 호출
        // result뷰컨을 해당 이미지들로 업데이트
        resultVC.updateTableView(with: ["house","sun.min","mic","mic.fill","trash"], section: .result)
    }
    
}

결과 화면  

여기서 뭔가 빠진 느낌이든다..

바로 3단 구성인데 결과화면은 하나만 쓸 수 있다.

그 뜻은 결과화면으로 화면 2개를 그려야한다는 뜻인데 여기서 나는 검색중에 보여주는 화면과 검색 후 결과화면을

각 시점에 맞는 트리거를 통해 바꿔끼는 작업을 진행해보려한다.

 

final class SearchResultViewController: BaseViewController<SearchResultViewModel> {
    
    private typealias DataSource = UITableViewDiffableDataSource<Section, CellData>
    private typealias Snapshot = NSDiffableDataSourceSnapshot<Section, CellData>
    let recommendTexts: [String] = ["Zedd", "Alan Walker", "David Guetta", "Avicii", "Marshmello", "Steve Aoki", "R3HAB", "Armin van Buuren", "Skrillex", "Illenium", "The Chainsmokers", "Don Diablo", "Afrojack", "Tiesto", "KSHMR", "DJ Snake", "Kygo", "Galantis", "Major Lazer", "Vicetone" ]
    
    var filteredArr: [String] = []
    
    private var dataSource: DataSource?
    
    private var tableView: UITableView = {
       let tableview = UITableView()
        tableview.backgroundColor = .white
        return tableview
    }()
    
    ...
    public func updateTableView(with datas: [String], section: Section) {
       var snapshot = Snapshot()
       snapshot.appendSections([section])

       switch section {
       case .recommend: // 추천 검색어
           snapshot.appendItems( datas.map{CellData.recommand(model: $0)} , toSection: section)

       case .result: // 검색 결과
           snapshot.appendItems( datas.map{CellData.result(model: $0)} , toSection: section)
       }

       dataSource?.apply(snapshot, animatingDifferences: false)
    }
    
}

extension SearchResultViewController: UISearchResultsUpdating {
    func updateSearchResults(for searchController: UISearchController) {
        guard let text = searchController.searchBar.text else { return }
        self.filteredArr = recommendTexts.filter{ $0.localizedStandardContains(text) }
        
        if searchController.isActive  { // 검색중일 경우 추천검색어 섹션에 필터링된 검색어 넣기
            updateTableView(with: filteredArr, section: .recommend)
        }
        
    }
    
}

 

updateTableVIew 함수를 통해 추천 검색어를 보여줄 지 검색 결과를 보여줄지 결정한다.

검색중은 UISearchResultUpdatin의 updateSearchResults 함수를 이용하고

검색 결과는 위에서 설명한 UISearchBarDelegate의 searchBarSearchButtonClicked를 이용한다.

 

다음 결과화면 영상을 보자.

 

 

 

검색 전 - 파란 임시뷰 

검색 중 - 필터링된 추천 검색어

검색 후 - 이미지 리스트 

 

한가지 SearchResultVC로 2개의 화면 [검색 중, 검색 후]을 모두 가지게 만들 수 있다.


UISearchBarToken

마지막으로 이번 미션에서 새롭게 알게된 개념이 서치바 토큰을 적용해보자.

아이콘과 함께 검색어를 묶어주는 토큰이다.

 

 

다음과 같이 searchBar -> searchTextField에 토큰고나련 다양한 프로퍼티와 메서드가 존재한다.

다음은 간단하게 버튼을 눌러 토큰을 추가해보는 것을 살펴보자.

button.addAction { [weak self] in
    guard let self else { return }
    self.searchController.searchBar.searchTextField.insertToken(UISearchToken(icon: UIImage(systemName: "person"), text: "사람"), at: .zero)
}

 

 

 


출처

 

UISearchController | Apple Developer Documentation

A view controller that manages the display of search results based on interactions with a search bar.

developer.apple.com

 

 

searchBar | Apple Developer Documentation

The search bar to install in your interface.

developer.apple.com

 

 

반응형

'iOS > UIKit' 카테고리의 다른 글

UIHostingController  (0) 2024.10.12
UIEditMenuInteraction  (3) 2024.10.12
NSKeyedArchiver  (0) 2024.09.11
NSCoding , NSSecureCoding  (0) 2024.09.10
NSObject  (2) 2024.09.10
'iOS/UIKit' 카테고리의 다른 글
  • UIHostingController
  • UIEditMenuInteraction
  • NSKeyedArchiver
  • NSCoding , NSSecureCoding
Hamp
Hamp
남들에게 보여주기 부끄러운 잡다한 글을 적어 나가는 자칭 기술 블로그입니다.
  • Hamp
    Hamp의 분리수거함
    Hamp
  • 전체
    오늘
    어제
    • 분류 전체보기 (311) N
      • CS (30)
        • 객체지향 (2)
        • Network (7)
        • OS (6)
        • 자료구조 (1)
        • LiveStreaming (3)
        • 이미지 (1)
        • 잡다한 질문 정리 (0)
        • Hardware (2)
        • 이론 (6)
        • 컴퓨터 그래픽스 (0)
      • Firebase (3)
      • Programing Langauge (39) N
        • swift (32)
        • python (6) N
        • Kotlin (1)
      • iOS (132)
        • UIKit (37)
        • Combine (1)
        • SwiftUI (32)
        • Framework (7)
        • Swift Concurrency (22)
        • Tuist (6)
        • Setting (11)
        • Modularization (1)
        • Instruments (6)
      • PS (59)
        • 프로그래머스 (24)
        • 백준 (13)
        • LeetCode (19)
        • 알고리즘 (3)
      • Git (18)
        • 명령어 (4)
        • 이론 (2)
        • hooks (1)
        • config (2)
        • action (7)
      • Shell Script (2)
      • Linux (6)
        • 명령어 (5)
      • Spring (15)
        • 어노테이션 (3)
        • 튜토리얼 (11)
      • CI-CD (4)
      • Android (0)
        • Jetpack Compose (0)
      • AI (3) N
        • 이론 (3) N
  • 블로그 메뉴

    • 홈
    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    dp
    GIT
    CS
    lifecycle
    UIKit
    Spring
    boostcamp
    SwiftUI
    투포인터
    dfs
    Tuist
    IOS
    dispatch
    concurrency
    Swift
    AVFoundation
    백준
    protocol
    프로그래머스
    property
  • 최근 댓글

  • 최근 글

  • 반응형
  • hELLO· Designed By정상우.v4.10.0
Hamp
UISearchController
상단으로

티스토리툴바