Customizing Annotation Callout Text

When presenting point data on your weather map using annotations, such as storm reports or earthquakes, the AerisWeather SDK for iOS will automatically format the text that is presented in an annotation’s callout view. In most cases this information will be sufficient. However, you may want to customize the text that is displayed for the title and/or subtitle of the annotation callout.

By default, each map layer type associated with point content sources has a style associated with it, which is either and instance of AWFAnnotationStyle or AWFGroupedStyle. Annotation callout text can be customized using the callout formatter block associated with the layer’s style.

Therefore, you will need to get the style associated with a particular layer type from your weather map and use the setCalloutFormatter method to override the default annotation callout text:

ObjectiveC
Swift
// get the current style instance associated with the earthquake layer
id<AWFStyleProvider> earthquakeStyle = [self.weatherMap.style styleForLayerType:AWFMapLayerEarthquakes];
    
// make sure style is an instance of AWFAnnotationStyle
if ([earthquakeStyle isKindOfClass:[AWFAnnotationStyle class]]) {
    // override the default callout formatter
    [(AWFAnnotationStyle *)earthquakeStyle setCalloutFormatter:^(NSObject<AWFAnnotation> * _Nonnull annotation) {
        // make sure the model object associated with the annotation is an AWFEarthquake instance
        if ([annotation.modelObject isKindOfClass:[AWFEarthquake class]]) {
            AWFEarthquake *report = (AWFEarthquake *)annotation.modelObject;
            
            // set the callout title text
            annotation.title = [NSString stringWithFormat:@"%.2f (%@)", report.magnitude, (report.type ? report.type : @"")];
            
            // set the callout subtitle text if `timestamp` is defined on the model
            if (report.timestamp) {
                annotation.subtitle = [report.timestamp awf_formattedDateWithFormat:@"M/d/y h:mm a" timeZone:report.place.timeZone];
            }
        }
    }];
}
// get the current style instance associated with the earthquake layer
if let earthquakeStyle = weatherMap.style.style(forLayerType: .earthquakes) as? AWFAnnotationStyle {
    
    // override the default callout formatter
    earthquakeStyle.setCalloutFormatter { (annotation) in
        // make sure model object associated with the annotation is an AWFEarthquake instance
        guard let report = annotation.modelObject as? AWFEarthquake else { return }
        
        // set the callout title text
        annotation.title = "\(report.magnitude) \(report.type ?? "")"
        
        // set the callout subtitle text if `timestamp` is defined on the model
        if let timestamp = report.timestamp, let timeZone = report.place?.timeZone {
            annotation.subtitle = "\((timestamp as NSDate).awf_formattedDate(withFormat: "M/d/y h:mm a", timeZone: timeZone) ?? "")"
        }
    }
}

Note that if you need to access data from the model object represented by an annotation, you can do so by accessing the modelObject property on the annotation passed to your callout formatter block. You will need to check the model object’s type and cast it to the appropriate type for the map layer before trying to access its properties.

Grouped Styles

If the style associated with a particular map layer is an AWFGroupedStyle instead of AWFAnnotationStyle, you will need to step through each style within the group and set the callout formatter. To do so, simply iterate through the values of a group’s styles property, which will be instances of AWFAnnotationStyle as mentioned above for single styles.

So we can use the same code as above, but we just move it into the iterator block for the group’s styles:

ObjectiveC
Swift
if ([earthquakeStyle isKindOfClass:[AWFGroupedStyle class]]) {
    // iterate through the style group's series of styles and set the callout formatter
    [((AWFGroupedStyle *)earthquakeStyle).styles enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, AWFMapItemStyle * _Nonnull style, BOOL * _Nonnull stop) {
        
        // make sure style is an instance of AWFAnnotationStyle
        if ([style isKindOfClass:[AWFAnnotationStyle class]]) {
            // override the default callout formatter
            [(AWFAnnotationStyle *)style setCalloutFormatter:^(NSObject<AWFAnnotation> * _Nonnull annotation) {
                // make sure the model object associated with the annotation is an AWFEarthquake instance
                if ([annotation.modelObject isKindOfClass:[AWFEarthquake class]]) {
                    AWFEarthquake *report = (AWFEarthquake *)annotation.modelObject;
                    
                    // set the callout title text
                    annotation.title = [NSString stringWithFormat:@"%.2f (%@)", report.magnitude, (report.type ? report.type : @"")];
                    
                    // set the callout subtitle text if `timestamp` is defined on the model
                    if (report.timestamp) {
                        annotation.subtitle = [report.timestamp awf_formattedDateWithFormat:@"M/d/y h:mm a" timeZone:report.place.timeZone];
                    }
                }
            }];
        }
    }];
}
if let group = weatherMap.style.style(forLayerType: .earthquakes) as? AWFGroupedStyle {
    // iterate through the style group's series of styles and set the callout formatter
    group.styles.forEach { (key, style) in
        // make sure style is an instance of AWFAnnotationStyle
        if let earthquakeStyle = style as? AWFAnnotationStyle {
            // override the default callout formatter
            earthquakeStyle.setCalloutFormatter { (annotation) in
                // make sure model object associated with the annotation is an AWFEarthquake instance
                guard let report = annotation.modelObject as? AWFEarthquake else { return }
                
                // set the callout title text
                annotation.title = "\(report.magnitude) \(report.type ?? "")"
                
                // set the callout subtitle text if `timestamp` is defined on the model
                if let timestamp = report.timestamp, let timeZone = report.place?.timeZone {
                    annotation.subtitle = "\((timestamp as NSDate).awf_formattedDate(withFormat: "M/d/y h:mm a", timeZone: timeZone) ?? "")"
                }
            }
        }
    }
}

Last modified: July 30, 2020