[iOS/Swift] Custom Annotation 만들어보기, Annotation image resizing하기
안녕하세요? 코코종입니다!!
오늘은 annotation을 커스텀해서 적용하는 방법을 들고왔습니다.
너무 오래전에 배웠던 MapKit에 대한 내용이라서 복습하는데 시간을 많이 소요했네요..^^
여담이지만 현재 교육과정의 19? 20?주차 쯤인데 4주차에 배웠던 내용이네요 허헣... 세월이 너무 빨라~~
Custom Annotation에 대한 기본적인 내용은 같이 SeSAC과정을 듣고 계신 마늘맨님의 블로그를 참고했습니다. 고마워요 마늘맨!
마늘맨님과 조금 다른 내용이라고 하면 Custom으로 Annotation과 AnnotationView를 만든것인데요! 일단 보시죠!
class CustomAnnotationView: MKAnnotationView {
static let identifier = "CustomAnnotationView"
override init(annotation: MKAnnotation?, reuseIdentifier: String?){
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
frame = CGRect(x: 0, y: 0, width: 40, height: 50)
centerOffset = CGPoint(x: 0, y: -frame.size.height / 2)
setupUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
backgroundColor = .clear
}
}
class CustomAnnotation: NSObject, MKAnnotation {
let sesac_image: Int?
let coordinate: CLLocationCoordinate2D
init(
sesac_image: Int?,
coordinate: CLLocationCoordinate2D
) {
self.sesac_image = sesac_image
self.coordinate = coordinate
super.init()
}
}
Custom으로 Annotation과 AnnotationView를 만든 이유는 바로 한 화면에서 여러가지 어노테이션을 써야하기 때문인데요.
예를 들면 지도에서 음식점의 종류에 따라서 다른 색으로 Annotation을 표시한다거나 하는 경우에 '음식점 종류'라는 파라미터가 필요할텐데 이를 위해서 커스텀으로 어노테이션을 만들어주는 겁니다. 저같은 경우에는 image_image(Int)에 따라서 다른 UIImage를 보여주고자 했습니다.
위의 사진처럼 다른 타입으로 어노테이션을 찍기 위해서 메서드를 만들고 viewDidLoad에서 실행해줬습니다.
// 기본적인 어노테이션
func addPin() {
let pin = MKPointAnnotation()
pin.coordinate = sesacCampusCoordinate
mapView.addAnnotation(pin)
}
// 커스텀한 어노테이션
func addCustomPin(sesac_image: Int, coordinate: CLLocationCoordinate2D) {
let pin = CustomAnnotation(sesac_image: sesac_image, coordinate: coordinate)
mapView.addAnnotation(pin)
}
MKMapViewDelegate를 이용해서 CustomAnnotation인 경우에 해당 어노테이션의 sesac_image값을 기준으로 이미지에 대한 분기처리를 했습니다. 추가적으로 어노테이션 이미지의 resizing에 대한 내용도 함께 있습니다.
extension HomeViewController: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard let annotation = annotation as? CustomAnnotation else {
return nil
}
var annotationView = self.mapView.dequeueReusableAnnotationView(withIdentifier: CustomAnnotationView.identifier)
if annotationView == nil {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: CustomAnnotationView.identifier)
annotationView?.canShowCallout = false
annotationView?.contentMode = .scaleAspectFit
} else {
annotationView?.annotation = annotation
}
let sesacImage: UIImage!
let size = CGSize(width: 85, height: 85)
UIGraphicsBeginImageContext(size)
switch annotation.sesac_image {
case 0:
sesacImage = UIImage(named: "sesac_face_1")
case 1:
sesacImage = UIImage(named: "sesac_face_2")
case 2:
sesacImage = UIImage(named: "sesac_face_3")
case 3:
sesacImage = UIImage(named: "sesac_face_4")
default:
sesacImage = UIImage(named: "sesac_face_1")
}
sesacImage.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
annotationView?.image = resizedImage
return annotationView
}
}
그리고 제가 하나 아주 골머리를 앓았던 오류가 있는데요. TableView나 CollectionView와 구성이 비슷하다는 말이 있어서 register에 대한 내용을 적었는데 오류가 발생하더라구요! 에러 메세지는 'Unrecognized selector sent to instance ~~' 라고 나오는데 디버그를 해보니 var annotationView를 선언하는 과정에서 오류가 발생하더라구요. 제 실수는 CustomAnnotationView.self로 register를 해야하는데 CustomAnnotation.self로 한 부분이었습니다.(register 부분에서 오류가 발생했으니 후에 사용할 때 오류가 발생했던 것입니다.(난 바보야...)
// 오류가 발생 한 부분
mapView.register(CustomAnnotation.self, forAnnotationViewWithReuseIdentifier: CustomAnnotationView.identifier)
// 수정한 부분
mapView.register(CustomAnnotationView.self, forAnnotationViewWithReuseIdentifier: CustomAnnotationView.identifier)
오늘은 저 멀리 기억속에 있던 MapKit에서 핀처럼 보이는 Annotation을 커스텀 하는 시간을 가져봤습니다!
생각보다 오류가 났던 부분이(저기 마지막에 쓴 register 오류) 시간을 오래 허비했는데 너무 어이없게 해결이 되어버리는 바람에 조금은 현타가 왔답니다 허헣...(사실 블로그에 글을 정리하면서 깨달았다는 소문이 수근수근)