[날씨 기본앱] #3 검색 화면 구현하기 - MapKit 을 알아보자

kimdocs...📄·2021년 9월 6일
0

CloneCoding💛

목록 보기
3/6
post-thumbnail

🐥 구현화면

1️⃣ MapKit을 알아보자!

애플 공식 문서를 참고해보세요!

Display map or satellite imagery within your app, call out points of interest, and determine placemark information for map coordinates.

MapKit 을 이용하면 앱 내에서 지도 또는 위성 이미지를 표시하고 원하는 지점을 호출할수 있으며 지도 좌표에 대한 장소 정보를 확인할 수 있습니다.

2️⃣ MapKit관련 변수 선언

   private var searchCompleter = MKLocalSearchCompleter()
   private var searchRegion: MKCoordinateRegion = MKCoordinateRegion(MKMapRect.world)
   private var searchResults = [MKLocalSearchCompletion]()
   
   private var places: MKMapItem? {
       didSet {
           resultTableView.reloadData()
       }
   }
   
   private var localSearch: MKLocalSearch? {
       willSet {
           // Clear the results and cancel the currently running local search before starting a new search.
           places = nil
           localSearch?.cancel()
       }
   }
  • MKLocalSearchCompleter
    사용자가 제공한 부분 검색 문자열을 기반으로 완료 문자열 목록을 생성하기 위한 객체입니다.
  • MKCoordinateRegion
    특정 위도와 경도를 중심으로 한 직사각형 지리적 영역
  • MKLocalSearchCompletion
    MKLocalSearchCompleter를 사용하여 부분 문자열을 기반으로 검색합니다.
  • MKMapItem
    지리적 위치와 해당 위치에 적용할 수 있는 정보(예: 해당 위치의 주소 및 해당 주소의 기업 이름)을 포함한 객체
  • MKLocalSearch
    지도 기반 검색을 시작하고 결과를 처리하기 위한 객체
    이 클래스를 사용하여 지도에서 주소를 검색할 수 있어요!

3️⃣ SearchCompleter

   searchCompleter.delegate = self
   searchCompleter.resultTypes = .address
   searchCompleter.region = searchRegion

4️⃣ UISearchBar

   extension SearchViewController: UISearchBarDelegate {
      func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
          if searchText.isEmpty {
              searchResults.removeAll()
              resultTableView.reloadData()
          }
          searchCompleter.queryFragment = searchText
      }
  }
  

searchCompleter에 검색문자 searchText를 넣어줍니다.

5️⃣ MKLocalSearchCompleterDelegate

  extension SearchViewController: MKLocalSearchCompleterDelegate {

      func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
          searchResults = completer.results
          resultTableView.reloadData()
      }

      func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) {
          if let error = error as NSError? {
              print("MKLocalSearchCompleter encountered an error: \(error.localizedDescription). The query fragment is: \"\(completer.queryFragment)\"")
          }
      }

  }
  
  • completerDidUpdateResults
    지정한 검색 완료자가 검색 완료 배열을 업데이트하면 호출됩니다.
    completer의 결과들을 searchResults객체에 담아주고 tableView를 reload해주어 결과들을 목록에 띄워줍니다.

5️⃣ UITableViewDelegate, UITableViewDataSource

검색 결과 cell 클릭시 MKLocalSearch에 Request를 보내줍니다.

response는 mapItems등을 담고있어요!
저는 경도 위도를 사용하여 날씨를 받아오는 api를 사용하였기 때문에 lat: placemark.coordinate.latitude, lon: placemark.coordinate.longitude로 경도 위도를 받아왔습니다.

  extension SearchViewController: UITableViewDelegate {
      func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
         let selectedResult = searchResults[indexPath.row]
         let searchRequest = MKLocalSearch.Request(completion: selectedResult)
         let search = MKLocalSearch(request: searchRequest)

         search.start { response, error in
          guard error == nil else {
              return
          }
          guard let placemark = response?.mapItems[0].placemark else { return }

          self.requestGetWeather(lat: placemark.coordinate.latitude, lon: placemark.coordinate.longitude, location: (placemark.locality ?? placemark.title) ?? "")
         }
     }
  }

  extension SearchViewController: UITableViewDataSource {
      func numberOfSections(in tableView: UITableView) -> Int {
          return 1
      }

      func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
          return searchResults.count
      }

      func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
          let cell = UITableViewCell()
          let searchResult = searchResults[indexPath.row]

          cell.textLabel?.font = .systemFont(ofSize: 16)
          cell.textLabel?.textColor = .gray
          cell.backgroundColor = .clear

          if let highlightText = searchBar.text {
              cell.textLabel?.setHighlighted(searchResult.title, with: highlightText)
          }

          return cell
      } 
  }

6️⃣ 검색 글자와 동일한 글자 Highlighted 주기


extension UILabel {
   func setHighlighted(_ text: String, with search: String) {
       let attributedText = NSMutableAttributedString(string: text)
       let range = NSString(string: text).range(of: search, options: .caseInsensitive)
       let highlightFont = UIFont.systemFont(ofSize: 16)
       let highlightColor = UIColor.white
       let highlightedAttributes: [NSAttributedString.Key: Any] = [ NSAttributedString.Key.font: highlightFont, NSAttributedString.Key.foregroundColor: highlightColor]
       
       attributedText.addAttributes(highlightedAttributes, range: range)
       self.attributedText = attributedText
   }
}

7️⃣ Search Bar 내부 textField 가져오기

let textFieldInsideSearchBar = $0.value(forKey: "searchField") as? UITextField
textFieldInsideSearchBar?.textColor = .white

📂 GitHub
https://github.com/ezidayzi/Moother_KimYoonSeo

profile
👩‍🌾 GitHub: ezidayzi / 📂 Contact: ezidayzi@gmail.com

0개의 댓글