본문 바로가기
iOS

[iOS/Swift] Custom Annotation 만들어보기, Annotation image resizing하기

by 코코종 2022. 2. 6.

 

안녕하세요? 코코종입니다!! 

오늘은 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 오류) 시간을 오래 허비했는데 너무 어이없게 해결이 되어버리는 바람에 조금은 현타가 왔답니다 허헣...(사실 블로그에 글을 정리하면서 깨달았다는 소문이 수근수근)