Аннотирование карт

Аннотации выводят на экран содержание, которое может быть определено единственной координатной точкой; оверлейные программы выводят на экран содержание, которое определяется любым числом очков и может составить одну или более непрерывных или форм состоящих из нескольких несмежных участков. Например, Вы используете аннотации для представления информации, такой как текущее расположение пользователя, определенный адрес или единственное интересное место. Вы используете оверлейные программы для представления более сложной информации, такой как маршруты или информация о трафике или границы областей, такие как парки, озера, города, состояния или страны.

В отличие от универсальных подпредставлений, аннотации и оверлейные программы остаются фиксированными к карте так, чтобы они переместились соответственно, когда пользователь масштабирует, панорамирования или прокрутки. В 3D карте аннотации поддерживают свою позицию, размер и ориентацию независимо от того, как карта вращается или делает подачу.

Набор карты разделяет данные, связанные с аннотацией или наложением от его визуального представления карты. Это разделение позволяет карте управлять видимыми аннотациями и оверлейными программами намного более эффективно: можно добавить сотни аннотаций и оверлейных программ к карте и все еще ожидать разумную производительность.

Добавление аннотаций к карте

Аннотации предлагают способ выделить определенные координаты на карте и предоставить дополнительную информацию о них. Можно использовать аннотации для вызова определенных адресов, интересных мест и других типов мест назначения. Когда выведено на экран на карте, аннотации обычно имеют своего рода изображение для идентификации их расположения и могут также иметь пузырь выноски предоставление информации и ссылок к большему количеству содержания. Рисунок 6-1 показывает аннотацию, использующую стандартное представление аннотации контакта для маркировки определенного расположения и обеспечивающую пузырь выноски, выводящий на экран дополнительную информацию включая индикатор раскрытия, приводящий к большему количеству подробных данных.

Рисунок 6-1  , Выводящий на экран аннотацию в карте

Для отображения аннотации на карту приложение должно обеспечить два отдельных объекта:

Объекты пометок являются обычно маленькими объектами данных, хранящими данные координаты карты и любую другую релевантную информацию об аннотации, такой как строка заголовка. Поскольку аннотации определяются с помощью протокола, можно повернуть любой класс в приложении в объект пометок. На практике хорошо сохранить легкий вес объектов пометок, особенно если Вы намереваетесь добавить большие количества их к карте. Представление карты сохраняет ссылку на объекты пометок, которые Вы добавляете к нему, и использует данные в тех объектах определить, когда вывести на экран соответствующее представление.

Набор карты обеспечивает некоторые стандартные представления аннотации, такие как аннотация контакта, и можно также определить пользовательские представления аннотации. Используете ли Вы стандартные или пользовательские представления аннотации, Вы не добавляете их непосредственно к поверхности карты. Вместо этого делегат карты обеспечивает представление аннотации, когда представление карты просит одно, и представление карты включает аннотацию в свою иерархию представления.

Аннотации, которые Вы создаете, обычно привязываются на единственной координате карты, не изменяющейся, но можно изменить координату аннотации программно в случае необходимости. Кроме того, можно реализовать поддержку, чтобы позволить пользователям перетаскивать аннотации вокруг карты.

Шаги для добавления аннотации к карте

Шаги для реализации и использования аннотаций в Вашем основанном на карте приложении показаны ниже. Предполагается, что Ваше приложение соединяется MKMapView возразите где-нибудь в его интерфейсе.

  1. Определите надлежащий объект пометок с помощью одной из следующих опций:

    • Используйте MKPointAnnotation класс для реализации простой аннотации. Этот тип аннотации содержит свойства для указания заголовка и строк подзаголовка для отображения в пузыре выноски аннотации.

    • Определите пользовательский объект, соответствующий MKAnnotation протокол, как описано в Определении Пользовательского Объекта пометок. Пользовательская аннотация может сохранить любой тип данных, которые Вы хотите.

  2. Определите представление аннотации для представления данных аннотации по экрану. То, как Вы определяете свое представление аннотации, зависит от Ваших потребностей и может быть одним из следующего:

  3. Реализуйте mapView:viewForAnnotation: метод в Вашей карте просматривает делегата.

    В Вашей реализации этого метода исключите существующее представление аннотации из очереди, если Вы существуете; в противном случае создайте новое представление аннотации. Если Ваши поддержки приложений многократные типы аннотаций, включайте логику в этот метод для создания представления надлежащего типа для предоставленного объекта пометок. Для получения дополнительной информации о реализации mapView:viewForAnnotation: метод, посмотрите Представления Аннотации Создания от Своего Объекта Делегата.

  4. Добавьте свой объект пометок к представлению карты с помощью addAnnotation: (или addAnnotations:) метод.

Когда Вы добавляете аннотацию к представлению карты, представление карты выводит на экран соответствующее представление аннотации каждый раз, когда координата для аннотации находится в видимом прямоугольнике карты. Если Вы хотите скрыть аннотации выборочно, необходимо вручную удалить их из карты, просматривают себя. Можно добавить и удалить аннотации в любое время.

Все аннотации составлены в том же масштабе каждый раз, независимо от текущего уровня изменения масштаба карты. Если Ваша карта содержит много аннотаций, Ваши представления аннотации могли бы перекрыть друг друга, поскольку пользователь уменьшает масштаб. Для противостояния этому поведению можно добавить и удалить аннотации на основе текущего уровня изменения масштаба карты. Например, когда карта уменьшена для показа всего состояния, погодное приложение могло бы вывести на экран информацию только для крупнейших городов. Поскольку пользователь увеличивает масштаб, приложение могло тогда добавить новые аннотации, содержащие информацию о погоде для меньших городов и областей. Реализация логики, необходимой, чтобы добавить и удалить аннотации, является Вашей ответственностью.

Для получения дополнительной информации о том, как эффективно управлять аннотациями представления карты, посмотрите Выводящие на экран Многократные Объекты пометок.

Определение пользовательского объекта пометок

Если все, что Вы хотите сделать, связать заголовок с координатой карты, можно использовать MKPointAnnotation класс для Вашего объекта пометок. Однако, если Вы хотите представлять дополнительную информацию с аннотацией, необходимо определить пользовательский объект пометок. Все объекты пометок должны соответствовать MKAnnotation протокол.

Пользовательский объект пометок состоит из координаты карты и безотносительно других данных, которые Вы хотите связать с аннотацией. Перечисление 6-1 показывает, что минимальный код должен был объявить пользовательский класс аннотации. coordinate объявление свойства от MKAnnotation протокол и должен быть включен во все классы аннотации. Поскольку это - простая аннотация, она также включает метод инициализатора, использующийся для установки значения только для чтения coordinate свойство. Ваше собственное объявление, вероятно, также включало бы методы и свойства, определяющие дополнительные данные аннотации.

Перечисление 6-1  , Создающее простой объект пометок

@interface MyCustomAnnotation : NSObject <MKAnnotation> {
    CLLocationCoordinate2D coordinate;
}
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
- (id)initWithLocation:(CLLocationCoordinate2D)coord;
 
// Other methods and properties.
@end

Ваш пользовательский класс должен реализовать координатное свойство и способ установить его значение. (Рекомендуется синтезировать coordinate потому что это гарантирует, что Набор Карты может автоматически обновить карту на основе изменений в свойстве.) Все, что остается, должно реализовать пользовательское initWithLocation: метод, показанный в Перечислении 6-2.

Перечисление 6-2  Реализовывая класс MyCustomAnnotation

@implementation MyCustomAnnotation
@synthesize coordinate;
 
- (id)initWithLocation:(CLLocationCoordinate2D)coord {
    self = [super init];
    if (self) {
        coordinate = coord;
    }
    return self;
}
@end

Для большего количества примеров объектов пометок см. проект примера кода MapCallouts.

Используя стандартные представления аннотации

Стандартные представления аннотации упрощают представлять аннотации на Вашу карту. MKAnnotationView класс определяет основное поведение для всех представлений аннотации. Например, MKPinAnnotationView подкласс MKAnnotationView дисплеи одна из стандартной системы прикрепляют изображения в координатной точке связанной аннотации. Можно также использовать MKAnnotationView вывести на экран пользовательское статическое изображение без разделения на подклассы.

Для отображения пользовательского изображения как аннотации создайте экземпляр MKAnnotationView и присвойте пользовательское изображение объекту image свойство. Когда аннотация выведена на экран, Ваше пользовательское изображение кажется, центрируемым по целевой координате карты. Если Вы не хотите, чтобы изображение центрировалось на координате карты, можно использовать centerOffset свойство для перемещения центральной точки в любое направление. Перечисление 6-3 показывает пример создания представления аннотации с пользовательским изображением, которое должно быть смещено вправо и выше координаты аннотации.

Перечисление 6-3  , Создающее стандартную аннотацию, просматривает с пользовательским изображением

MKAnnotationView* aView = [[MKAnnotationView alloc] initWithAnnotation:annotation
                                  reuseIdentifier:@"MyCustomAnnotation"];
aView.image = [UIImage imageNamed:@"myimage.png"];
aView.centerOffset = CGPointMake(10, -20);

Вы создаете стандартные представления аннотации в своем делегате mapView:viewForAnnotation: метод. Для получения дополнительной информации о том, как реализовать этот метод, посмотрите Представления Аннотации Создания от Своего Объекта Делегата.

Определение пользовательского представления аннотации

Если статическое изображение недостаточно для представления Вашей аннотации, можно разделить на подклассы MKAnnotationView и нарисуйте содержание динамично одним из следующих двух способов:

  • Продолжайте использовать image свойство MKAnnotationView, но измените изображение равномерно.

  • Переопределите представление аннотации drawRect: метод и рисует Ваше содержание динамично каждый раз.

Как с любым пользовательским получением Вы делаете в представлении, всегда рассматриваете производительность прежде, чем выбрать подход. Несмотря на то, что пользовательское получение дает Вам, наибольшая гибкость, с помощью изображений может быть быстрее, особенно если фиксируется большая часть содержания.

Когда Вы используете drawRect: метод для рисования содержания укажите ненулевой тип телосложения для представления аннотации вскоре после инициализации, чтобы гарантировать, что представленное содержание становится видимым. Указание ненулевого типа телосложения необходимо, потому что метод инициализации по умолчанию для представлений аннотации использует изображение, указанное в image свойство для установки типа телосложения позже. При рисовании изображения вместо того, чтобы установить свойство необходимо установить frame свойство представления явно или Вашего представленного содержания не будет видимо. И потому что представление подходит к концу только часть своего кадра, установите его opaque свойство к NO так, чтобы остающееся содержание карты показало через. Если Вы не устанавливаете opaque свойство, система получения заполняет Ваше представление текущим фоновым цветом прежде, чем вызвать drawRect: метод. Перечисление 6-4 показывает метод инициализации в качестве примера, устанавливающий тип телосложения и непрозрачность пользовательского представления аннотации.

Перечисление 6-4  , Инициализирующее пользовательское представление аннотации

- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
    if (self)
    {
        // Set the frame size to the appropriate values.
        CGRect  myFrame = self.frame;
        myFrame.size.width = 40;
        myFrame.size.height = 40;
        self.frame = myFrame;
 
        // The opaque property is YES by default. Setting it to
        // NO allows map content to show through any unrendered parts of your view.
        self.opaque = NO;
    }
    return self;
}

В большинстве отношений, таща пользовательское содержание в представлении аннотации совпадает с ним, находится в любом представлении. Системные вызовы Ваше представление drawRect: метод для перерисовки частей представления, которым нужен он, и можно вызвать работу перерисовки путем вызова setNeedsDisplay или setNeedsDisplayInRect: метод Вашего представления в любое время. Если Вы хотите анимировать содержание своего представления, установите таймер, чтобы выстрелить в периодические интервалы и обновить Ваше представление. Для установки таймеров посмотрите, что Таймер Программирует Темы. Чтобы узнать больше, как представления рисуют содержание, см. Руководство по программированию Представления для iOS или Руководства по Рисованию Какао (для получения информации о OS X).

Создание представлений аннотации от Вашего объекта делегата

Когда для представления карты нужно представление аннотации, оно вызывает mapView:viewForAnnotation: метод его объекта делегата. Если Вы не реализуете этот метод — или если Вы реализуете его и всегда возвращаетесь nil— представление карты использует представление аннотации по умолчанию, которое обычно является представлением аннотации контакта. Если Вы хотите возвратить представления аннотации кроме по умолчанию, необходимо переопределить mapView:viewForAnnotation: и создайте свои представления там.

Прежде, чем создать новое представление в mapView:viewForAnnotation: метод, всегда проверяйте, чтобы видеть, существует ли уже подобное представление аннотации. Представление карты имеет опцию кэширования неиспользованных представлений аннотации, что это не использует, таким образом, неиспользованное представление может быть доступным от dequeueReusableAnnotationViewWithIdentifier: метод. Если исключающий из очереди метод возвращает значение кроме nil, обновите атрибуты представления и возвратите его; если возвращается метод nil, создайте новый экземпляр надлежащего класса представления аннотации. В обоих случаях это - Ваша ответственность взять аннотацию, переданную этому методу и присвоить его своему представлению аннотации. Также используйте mapView:viewForAnnotation: обновить представление прежде, чем возвратить его.

Перечисление 6-5 показывает реализацию в качестве примера mapView:viewForAnnotation: метод, обеспечивающий представления аннотации контакта для пользовательских объектов пометок. Если существующее представление аннотации контакта уже существует, этот метод связывает объект пометок с тем представлением. Если никакое представление не находится в очереди повторного использования, этот метод создает новый и устанавливает его основные свойства. Если карта в настоящее время показывает расположение пользователя, этот метод возвраты nil для любого MKUserLocation объекты так, чтобы карта использовала представление аннотации по умолчанию. (Вы также настроили бы выноску в mapView:viewForAnnotation: метод; посмотрите Выноски Создания.)

Перечисление 6-5  , Создающее представления аннотации

- (MKAnnotationView *)mapView:(MKMapView *)mapView
                      viewForAnnotation:(id <MKAnnotation>)annotation
{
    // If the annotation is the user location, just return nil.
    if ([annotation isKindOfClass:[MKUserLocation class]])
        return nil;
 
    // Handle any custom annotations.
    if ([annotation isKindOfClass:[MyCustomAnnotation class]])
    {
        // Try to dequeue an existing pin view first.
        MKPinAnnotationView*    pinView = (MKPinAnnotationView*)[mapView
        dequeueReusableAnnotationViewWithIdentifier:@"CustomPinAnnotationView"];
 
        if (!pinView)
        {
            // If an existing pin view was not available, create one.
            pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation
                       reuseIdentifier:@"CustomPinAnnotationView"];
            pinView.pinColor = MKPinAnnotationColorRed;
            pinView.animatesDrop = YES;
            pinView.canShowCallout = YES;
 
            // If appropriate, customize the callout by adding accessory views (code not shown).
        }
        else
            pinView.annotation = annotation;
 
        return pinView;
    }
 
    return nil;
}

Создание выносок

Выноска является стандартным или пользовательским представлением, которое может появиться с представлением аннотации. Стандартная выноска выводит на экран заголовок аннотации, и это может вывести на экран дополнительное содержание, такое как подзаголовок, изображения и управление. Если Вы хотите вывести на экран пользовательское представление, ведущее себя как выноска, добавьте, что пользовательское подпредставление к аннотации просматривает и обновляет метод тестирования хита представления аннотации обработать взаимодействие с пользователем с подпредставлением.

Используя стандартную выноску самый простой способ вывести на экран пользовательское содержание, не создавая пользовательское подпредставление. Например, рисунок 6-2 показывает стандартную выноску, это было изменено для отображения пользовательского изображения, и подробная кнопка раскрытия (Перечисление 6-6 показывает код, создающий эту измененную выноску).

Рисунок 6-2  стандартная выноска, измененная для включения пользовательского изображения и кнопки раскрытия

Перечисление 6-6  Настраивая стандартную выноску

// This code snippet assumes that an annotation for the Golden Gate Bridge has already been added to the map view.
 
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
// Try to dequeue an existing pin view first (code not shown).
 
// If no pin view already exists, create a new one.
MKPinAnnotationView *customPinView = [[MKPinAnnotationView alloc]
                                             initWithAnnotation:annotation reuseIdentifier:BridgeAnnotationIdentifier];
customPinView.pinColor = MKPinAnnotationColorPurple;
customPinView.animatesDrop = YES;
customPinView.canShowCallout = YES;
 
// Because this is an iOS app, add the detail disclosure button to display details about the annotation in another view.
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:nil action:nil forControlEvents:UIControlEventTouchUpInside];
customPinView.rightCalloutAccessoryView = rightButton;
 
      // Add a custom image to the left side of the callout.
UIImageView *myCustomImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"MyCustomImage.png"]];
customPinView.leftCalloutAccessoryView = myCustomImage;
 
return customPinView;
}

В приложении для iOS это - хорошая практика для использования mapView:annotationView:calloutAccessoryControlTapped: метод делегата ответить, когда пользователи касаются управления представления выноски (как долго, поскольку управление является потомком UIControl). В Вашей реализации этого метода можно обнаружить идентификационные данные представления аннотации представления выноски так, чтобы Вы знали, какой аннотации пользователь коснулся. В приложении Mac контроллер представления представления выноски может реализовать метод действия, отвечающий, когда пользователь щелкает по управлению в представлении выноски.

При использовании пользовательского представления вместо стандартной выноски необходимо выполнить дополнительную работу, чтобы удостовериться, что выноска показывает и скрывается соответственно, когда пользователи взаимодействуют с ним. Шаги ниже обрисовывают в общих чертах процесс для создания пользовательской выноски, содержащей кнопку:

  1. Разработайте NSView или UIView подкласс, представляющий пользовательскую выноску. Вероятно, что подкласс должен реализовать drawRect: метод для рисования пользовательского содержания.

  2. Создайте контроллер представления, инициализирующий представление выноски и выполняющий действие, связанное с кнопкой.

  3. В представлении аннотации, реализации hitTest: реагировать на хиты, которые являются вне границ представления аннотации, но в границах представления выноски, как показано в Перечислении 6-7.

  4. В представлении аннотации, реализации setSelected:animated: для добавления выноски просматривают как подпредставление представления аннотации когда пользовательские щелчки или касания это. Если представление выноски уже видимо, когда пользователь выбирает его, setSelected: метод должен удалить подпредставление выноски из представления аннотации (см. Перечисление 6-8).

  5. В представлении аннотации initWithAnnotation: метод, набор canShowCallout свойство к NO препятствовать тому, чтобы карта вывела на экран стандартную выноску, когда пользователь выбирает аннотацию.

Перечисление 6-7 показывает пример реализации hitTest: обработать хиты в представлении выноски, которое могло бы быть вне границ представления аннотации.

Перечисление 6-7  , Отвечающее на хиты в пользовательской выноске

- (NSView *)hitTest:(NSPoint)point
{
    NSView *hitView = [super hitTest:point];
    if (hitView == nil && self.selected) {
        NSPoint pointInAnnotationView = [self.superview convertPoint:point toView:self];
        NSView *calloutView = self.calloutViewController.view;
        hitView = [calloutView hitTest:pointInAnnotationView];
    }
    return hitView;
}

Перечисление 6-8 показывает пример реализации setSelected:animated: когда пользователь выбирает представление аннотации, для анимации поступления и увольнения пользовательской выноски просматривают.

  Добавление перечисления 6-8 и удаление пользовательского представления выноски

- (void)setSelected:(BOOL)selected
{
    [super setSelected:selected];
 
    // Get the custom callout view.
    NSView *calloutView = self.calloutViewController.view;
    if (selected) {
        NSRect annotationViewBounds = self.bounds;
        NSRect calloutViewFrame = calloutView.frame;
      // Center the callout view above and to the right of the annotation view.
        calloutViewFrame.origin.x = -(NSWidth(calloutViewFrame) - NSWidth(annotationViewBounds)) * 0.5;
        calloutViewFrame.origin.y = -NSHeight(calloutViewFrame) + 15.0;
        calloutView.frame = calloutViewFrame;
 
        [self addSubview:calloutView];
    } else {
        [calloutView.animator removeFromSuperview];
    }
}

Отображение многократных объектов пометок

Если Ваше приложение работает с больше, чем несколькими аннотациями, Вы, возможно, должны были бы думать о том, как Вы выводите на экран их. Представление карты рассматривает все объекты пометок, которые оно знает собирающийся быть активным, и в результате оно всегда пытается вывести на экран соответствующее представление аннотации, когда данная координатная точка находится на экране. Если координаты для двух аннотаций близко друг к другу, это могло бы вести для наложения между соответствующими представлениями аннотации. Если Ваша карта включает сотни аннотаций, уменьшение масштаб достаточно далеко могло бы привести к визуально непривлекательной массе представлений аннотации. Еще хуже, аннотации могут быть так близко друг к другу, что пользователь не может получить доступ к некоторым из них.

Единственный способ устранить переполнение аннотации состоит в том, чтобы удалить некоторые объекты пометок от представления карты. Это обычно включает реализацию mapView:regionWillChangeAnimated: и mapView:regionDidChangeAnimated: методы для обнаружения изменений в карте масштабируют уровень. Во время изменения изменения масштаба можно добавить или удалить аннотации по мере необходимости на основе их близости к друг другу. Вы могли бы также полагать, что другие критерии (такие как текущее расположение пользователя) устранили некоторые аннотации.

Набор карты включает многочисленные функции, делающие определение близости точек карты проще. При преобразовании координаты карты аннотации к координатному пространству точки карты можно использовать MKMetersBetweenMapPoints метод для получения абсолютного расстояния между двумя точками. Можно также использовать каждую координату в качестве центра прямоугольника карты и использовать MKMapRectIntersectsRect функционируйте для нахождения любых пересечений. Для полного списка функций посмотрите Ссылку Функций MapKit.

Отмечание представления аннотации как перемещаемое

Представления аннотации предоставляют встроенную поддержку перетаскивания, делающую очень простым перетащить аннотации вокруг карты и гарантировать, что данные аннотации обновляются соответственно. Реализовать минимальную поддержку перетаскивания:

  • В Ваших объектах пометок реализуйте setCoordinate: метод для разрешения карты просматривает для обновления координатной точки аннотации.

  • При создании представления аннотации, набор draggable свойство к YES.

Когда пользователь касается и придерживается перемещаемого взгляда аннотации, представление карты начинает работу перетаскивания для него. В то время как работа перетаскивания развивается, представление карты вызывает mapView:annotationView:didChangeDragState:fromOldState: метод его делегата для уведомления его относительно изменений в состоянии перетаскивания представления. Можно использовать этот метод, чтобы влиять или реагировать на работу перетаскивания.

Для анимации представления во время работы перетаскивания реализуйте пользовательское dragState метод в Вашем представлении аннотации. Поскольку процессы представления карты перетаскивают связанные сенсорные события, это обновляет dragState свойство затронутого представления аннотации. Реализация пользовательского dragState метод дает Вам шанс прервать эти изменения и выполнить дополнительные действия, такие как анимация появления Вашего представления. Например, MKPinAnnotationView класс повышает контакт от карты, когда работа перетаскивания запускает и роняет контакт вниз на карте, когда это заканчивается.

Отображение оверлейных программ на карте

Оверлейные программы предлагают способ разделить содержание на уровни по произвольной области карты. Принимая во внимание, что аннотации всегда определяются единственной координатой карты, оверлейные программы обычно определяются многократными координатами. Можно использовать эти координаты для создания непрерывных или наборов состоящих из нескольких несмежных участков строк, прямоугольников, кругов и других форм, которые могут тогда быть заполнены или перечеркнуться цветом. Например, Вы могли бы использовать оверлейные программы, чтобы разделить информацию о трафике на уровни поверх шоссе, выделить границы парка или показать город, состояние и национальные границы. Рисунок 6-3 показывает заполненное и перечеркиваемое наложение, покрывающее Колорадо.

Рисунок 6-3  , Выводящий на экран наложение на карте

Для отображения наложения на карте приложение должно обеспечить два отдельных объекта:

Объекты наложения являются обычно маленькими объектами данных, хранящими точки, определяющие наложение и любую другую релевантную информацию, такую как строка заголовка. Поскольку оверлейные программы определяются с помощью протокола, можно повернуть любой класс в приложении в объект наложения. Кроме того, Набор Карты определяет несколько конкретных объектов наложения для указания различных типов стандартных форм. Представление карты сохраняет ссылку на объекты наложения, которые Вы добавляете к нему, и использует данные в тех объектах определить, когда вывести на экран соответствующее представление.

Набор карты обеспечивает стандартные средства рендеринга наложения, которые могут нарисовать любые формы, представленные конкретными объектами наложения. Как с аннотациями, Вы не добавляете средства рендеринга наложения непосредственно к поверхности карты. Вместо этого объект делегата обеспечивает средство рендеринга наложения, когда представление карты просит одно, и представление карты включает наложение в свою непрозрачную иерархию представления.

Как правило, координаты наложения на карте никогда не изменяются. Несмотря на то, что возможно создать перемещаемые оверлейные программы, делание так редко. Необходимо было бы реализовать код для отслеживания работы перетаскивания, и необходимо обновить точки координаты наложения сами.

Шаги для добавления наложения к карте

Вот шаги для реализации и использования оверлейных программ в Вашем основанном на карте приложении. Предполагается, что Ваше приложение соединяется MKMapView возразите где-нибудь в его интерфейсе.

  1. Определите надлежащий объект данных наложения с помощью одной из следующих опций:

    • Используйте MKCircle, MKPolygon, или MKPolyline класс как есть.

    • Используйте MKTileOverlay класс, если Ваше наложение представлено набором пользовательских растровых мозаик.

    • Подкласс MKShape или MKMultiPoint создать оверлейные программы, обеспечивающие специфичные для приложения способы поведения или использующие пользовательские формы.

    • Используйте существующий класс из своего приложения и заставьте его соответствовать MKOverlay протокол.

  2. Определите средство рендеринга наложения для представления наложения на экране с помощью одной из следующих опций:

    • Для стандартных форм используйте MKCircleRenderer, MKPolygonRenderer, или MKPolylineRenderer класс для представления наложения. Можно настроить многие атрибуты получения заключительной формы с помощью этих классов.

    • Для мозаичного наложения используйте MKTileOverlayRenderer класс для обработки получения мозаик на карте.

    • Поскольку пользовательские формы убывали от MKShape, определите надлежащий подкласс MKOverlayPathRenderer представлять форму.

    • Для всех других пользовательских форм и оверлейных программ, подкласса MKOverlayRenderer и реализуйте свой пользовательский код для прорисовки.

  3. Реализуйте mapView:rendererForOverlay: метод в Вашей карте просматривает делегата.

  4. Добавьте свой объект данных наложения к представлению карты с помощью addOverlay: метод или один из многих других.

В отличие от аннотаций, представленных оверлейными программами, автоматически масштабируются для соответствия текущего уровня изменения масштаба карты. Масштабирование наложения необходимо, потому что оверлейные программы обычно выделяют границы, дороги и другое содержание, также масштабирующееся во время изменения масштаба.

Можно перестроить Z-упорядочивание оверлейных программ в карте, чтобы гарантировать, что определенные оверлейные программы всегда выводятся на экран поверх других. И, для указания уровня наложения относительно другого содержания карты, такого как дороги, метки и представления аннотации, используют один из MKOverlayLevel константы:

  • MKOverlayLevelAboveRoads

  • MKOverlayLevelAboveLabels

Оверлейные программы могут дополнить или заменить предоставленное системой содержание карты. Если Ваше наложение непрозрачно, используйте canReplaceMapContent свойство для предотвращения системы от ненужной загрузки и рисования содержания карты, которое пользователи не будут видеть позади наложения.

Используя стандартные объекты наложения и представления

Если все, что Вы хотите сделать, выделить определенную область карты, использование стандартных классов наложения является самым простым способом сделать это. Стандартные классы наложения включают MKCircle, MKPolygon, и MKPolyline. Эти классы определяют основную форму наложения и используются в сочетании с MKCircleRenderer, MKPolygonRenderer, или MKPolylineRenderer классы, обрабатывающие рендеринг той формы на поверхности карты.

Перечисление 6-9 показывает пример того, как Вы создали бы прямоугольный многоугольник, показанный на рисунке 6-3. Этот многоугольник состоит из четырех координат карты, соответствующих четырем углам Колорадо. После создания многоугольника все, что необходимо сделать, добавляет это к карте с помощью addOverlay: метод.

Перечисление 6-9  , Создающее объект наложения многоугольника

    // Define an overlay that covers Colorado.
    CLLocationCoordinate2D  points[4];
 
    points[0] = CLLocationCoordinate2DMake(41.000512, -109.050116);
    points[1] = CLLocationCoordinate2DMake(41.002371, -102.052066);
    points[2] = CLLocationCoordinate2DMake(36.993076, -102.041981);
    points[3] = CLLocationCoordinate2DMake(36.99892, -109.045267);
 
    MKPolygon* poly = [MKPolygon polygonWithCoordinates:points count:4];
    poly.title = @"Colorado";
 
    [map addOverlay:poly];

Для наложения, которое будет показано на карте, mapView:viewForOverlay: метод Вашего делегата представления карты должен обеспечить надлежащее средство рендеринга наложения. Для стандартных форм наложения можно сделать это путем создания средства рендеринга, соответствующего тип формы, которую Вы хотите вывести на экран. Перечисление 6-10 показывает реализацию этого метода, создающего средство рендеринга многоугольника, используемое для покрытия Колорадо. В этом примере метод выбирает цвета для использования для рендеринга формы и ширины рамки.

Перечисление 6-10  , Создающее средство рендеринга многоугольника для рендеринга формы

- (MKOverlayRenderer *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
    if ([overlay isKindOfClass:[MKPolygon class]])
    {
        MKPolygonRenderer*    aRenderer = [[MKPolygonRenderer alloc] initWithPolygon:(MKPolygon*)overlay];
 
        aRenderer.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
        aRenderer.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
        aRenderer.lineWidth = 3;
 
        return aRenderer;
    }
 
    return nil;
}

Важно помнить, что стандартные средства рендеринга наложения просто заполняют и перечеркивают форму, представленную наложением. Если Вы хотите вывести на экран дополнительную информацию, необходимо создать пользовательское средство рендеринга наложения, чтобы сделать необходимое получение. Необходимо избежать добавлять подпредставления к существующему наложению в попытке представить любое дополнительное содержание. Любые подпредставления, которые Вы добавляете к наложению, масштабируются вместе с самим наложением и делаются соответствовать уровню изменения масштаба карты. Если Ваши подпредставления не содержат содержание, также масштабирующееся хорошо, результаты, вероятно, не выглядели бы очень хорошими.

Работа с мозаичными оверлейными программами

При использовании пользовательских растровых мозаик для обеспечения наложения, можно использовать MKTileOverlay управлять мозаиками и MKTileOverlayRenderer представить их. Сингл MKTileOverlay объект может обработать мозаики для многократных уровней изменения масштаба, потому что шаблон URL класса позволяет Вам указать позицию карты мозаики, масштабируйте уровень и масштабный коэффициент, в дополнение к его расположению в комплекте приложений или на сервере.

По умолчанию верхний левый угол карты является источником для значений x и y мозаики. (Можно использовать geometryFlipped свойство для перемещения источника в нижний левый угол, но если Вы хотите использовать пользовательскую схему индексации, необходимо разделить на подклассы MKTileOverlay.) Каждый уровень изменения масштаба увеличивает или сокращает число мозаик питанием два. Например, уровень изменения масштаба трех средних значений, что существует восемь мозаик в обоих направления x и y.

Для создания мозаик, соответствующих искривление карты используйте сферическую Меркаторскую систему координат проекции EPSG:3857.

Определение пользовательского объекта наложения

Задание объекта наложения должно управлять координатными данными и любой дополнительной информацией, связанной с наложением. Набор карты предоставляет следующие возможности для определения пользовательских оверлейных программ:

  • Принятие MKOverlay протокол в одном из существующих классов Вашего приложения

  • Разделение на подклассы MKShape или MKMultiPoint определить новые типы основанных на форме оверлейных программ

  • Разделение на подклассы MKTileOverlay управлять мозаиками, использующими пользовательскую схему индексации

Разделяете ли Вы на подклассы или принимаете MKOverlay протокол, работа, которую необходимо выполнить в пользовательском объекте наложения, в основном то же. Основное задание объекта наложения должно продать две основных части информации:

  • Координата, определяющая центральную точку наложения

  • Ограничительный прямоугольник, полностью охватывающий содержание наложения

Ограничительный прямоугольник является самыми важными данными к самому наложению. Представление карты использует ограничительный прямоугольник, указанный объектом наложения как его сигнал для того, когда добавить соответствующее средство рендеринга наложения к карте. (Если Вы добавляете наложение к карте как аннотация также, координатное значение так же определяет, когда соответствующее представление аннотации должно быть добавлено к карте.) Сам ограничительный прямоугольник должен быть указан с помощью точек карты, не отобразить координаты. Можно преобразовать между этими двумя системами координат с помощью функций Набора Карты.

Большая часть работы, связанной с отображением наложения, выполнена соответствующим объектом средства рендеринга наложения. Объект наложения просто определяет, куда на карте наложение должно быть помещено, тогда как средство рендеринга наложения определяет заключительное появление наложения, включая то, какая информация (если таковые имеются) выведена на экран для наложения. Создание пользовательских средств рендеринга наложения описано далее в Определении Пользовательского Средства рендеринга Наложения.

Определение пользовательского средства рендеринга наложения

Если Вы хотите сделать больше, чем проводят границы или заполняют содержание Вашей формы наложения, необходимо создать пользовательское средство рендеринга наложения. Например, при рисовании наложения трафика Вы могли бы использовать пользовательское средство рендеринга наложения, чтобы нанести цветную маркировку на каждое шоссе на основе его условий. Можно также использовать пользовательский код для прорисовки для анимации появления наложения.

Для создания пользовательского средства рендеринга наложения необходимо разделить на подклассы MKOverlayRenderer. (Если Вы просто хотите изменить поведение получения существующего основанного на форме наложения, можно разделить на подклассы MKOverlayPathRenderer вместо этого.)

В Вашей пользовательской реализации MKOverlayRenderer, необходимо реализовать следующие методы:

  • drawMapRect:zoomScale:inContext: нарисовать Ваше пользовательское содержание

  • canDrawMapRect:zoomScale: если Ваш код для прорисовки зависит от содержания, которое не могло бы всегда быть доступно

canDrawMapRect:zoomScale: метод для ситуаций, где Ваше содержание может не всегда быть готово нарисовать. Например, наложение трафика должно было бы загрузить необходимые данные трафика с сети, прежде чем это могло нарисовать. Если Вы возвращаетесь NO от этого метода представление карты воздерживается от рисования Вашего наложения, пока Вы не сигнализируете, что Вы готовы. Можно сделать это путем маркировки представления как грязное использование любого setNeedsDisplayInMapRect: или setNeedsDisplayInMapRect:zoomScale: метод.

Когда Ваше представление готово нарисовать, представление карты вызывает drawMapRect:zoomScale:inContext: метод, чтобы сделать фактическое получение. (Обратите внимание на то, что, если необходимо выполнить обработку изображений на мозаиках, поскольку они рисуются, необходимо разделить на подклассы MKTileOverlayRenderer.) В отличие от рисования в нормальном представлении, рисующем в представлении наложения, требует специальных замечаний:

  • В Вашем коде для прорисовки никогда не используйте границы представления или кадр как контрольные точки для рисования. Вместо этого используйте точки карты, связанные с объектом наложения для определения форм. Сразу перед получением, код должен преобразовать те, карта указывает на точки (CGPoint и т.д.) использование подпрограмм преобразования, найденных в MKOverlayRenderer класс.

    Кроме того, Вы обычно не применяетесь, значение масштаба изменения масштаба передало этому методу непосредственно к Вашему содержанию. Вместо этого Вы обеспечиваете его только, когда функция Набора Карты или метод в частности требуют его. Пока Вы указываете довольный точки карты использования и преобразовываете в точки, Ваше содержание должно масштабироваться к корректному размеру автоматически.

  • Если Вы используете классы UIKit и функции, чтобы нарисовать, явно установить и очистить среду получения. Прежде, чем издать любые приказы, вызовите UIGraphicsPushContext функция для создания контекста передала методу текущий контекст. Когда Вы закончите рисовать, вызвать UIGraphicsPopContext удалить тот контекст.

  • Помните, что представление карты может разместить большие оверлейные программы рядом и представить каждую мозаику на отдельном потоке. Ваш код для прорисовки не должен поэтому пытаться изменить переменные или другие данные, если это не может сделать так ориентированным на многопотоковое исполнение способом.

Перечисление 6-11 показывает, что код для прорисовки раньше заполнял ограничительный прямоугольник наложения с помощью градиента. При рисовании градиентов особенно важно содержать операцию рисования путем применения прямоугольника отсечения к желаемой области получения. Кадр представления фактически больше, чем ограничительный прямоугольник наложения, таким образом, без прямоугольника отсечения, градиент представил бы вне ожидаемой области. Поскольку ограничительный прямоугольник наложения определяет фактическую форму в этом случае, этот метод просто отсекает к ограничительному прямоугольнику. Для более сложных оверлейных программ Вы хотели бы отсечь к пути, представляющему Ваше наложение. Результаты этого кода для прорисовки показаны на рисунке 6-4.

Перечисление 6-11  , Получающее градиент в пользовательском наложении

- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context
{
   // Get the overlay bounding rectangle.
   MKMapRect  theMapRect = [self.overlay boundingMapRect];
   CGRect theRect = [self rectForMapRect:theMapRect];
 
   // Clip the context to the bounding rectangle.
   CGContextAddRect(context, theRect);
   CGContextClip(context);
 
   // Set up the gradient color and location information.
   CGColorSpaceRef myColorSpace = CGColorSpaceCreateDeviceRGB();
   CGFloat locations[4] = {0.0, 0.33, 0.66, 1.0};
   CGFloat components[16] = {0.0, 0.0, 1.0, 0.5,
                             1.0, 1.0, 1.0, 0.8,
                             1.0, 1.0, 1.0, 0.8,
                             0.0, 0.0, 1.0, 0.5};
 
   // Create the gradient.
   CGGradientRef myGradient = CGGradientCreateWithColorComponents(myColorSpace, components, locations, 4);
   CGPoint start, end;
   start = CGPointMake(CGRectGetMidX(theRect), CGRectGetMinY(theRect));
   end = CGPointMake(CGRectGetMidX(theRect), CGRectGetMaxY(theRect));
 
   // Draw.
   CGContextDrawLinearGradient(context, myGradient, start, end, 0);
 
   // Clean up.
   CGColorSpaceRelease(myColorSpace);
   CGGradientRelease(myGradient);
}

Рисунок 6-4 показывает результаты рисования пользовательского содержания по наложению для Колорадо. В этом случае средство рендеринга наложения заполняет свое содержание пользовательским градиентом.

Рисунок 6-4  Используя пользовательское средство рендеринга наложения для рисования

Создание средств рендеринга наложения от объекта делегата

Когда этому нужно средство рендеринга наложения, представление карты вызывает mapView:rendererForOverlay: метод его объекта делегата. Если Вы не реализуете этот метод — или если Вы реализуете его и всегда возвращаетесь nil— представление карты ничего не выводит на экран для указанного наложения. Поэтому необходимо реализовать этот метод и возвратить допустимое средство рендеринга наложения для любых оверлейных программ, которые Вы хотите выведенный на экран на карте.

По большей части каждое наложение отличается. Несмотря на то, что необходимо всегда создавать средства рендеринга наложения в Вашем mapView:rendererForOverlay: метод, Вы, возможно, должны быть немного более творческими в том, как Вы конфигурируете те объекты. Если все Ваши средства рендеринга совместно используют те же атрибуты получения, можно реализовать этот метод в пути, подобном один показанный в Перечислении 6-10. Однако, если каждое наложение использует различные цвета или рисующие атрибуты, необходимо найти способ инициализировать ту информацию с помощью объекта пометок, вместо того, чтобы иметь большое дерево решений в mapView:rendererForOverlay:.

Поскольку оверлейные программы обычно отличаются от друг друга, представление карты не перерабатывает те объекты, когда они удалены из карты. Вместо исключения из очереди существующее средство рендеринга наложения, необходимо создать новое каждый раз.

Отображение многократных объектов наложения

Если Ваше приложение работает больше чем с одним наложением, Вы, возможно, должны были бы думать о том, как управлять теми объектами. Когда любая часть наложения пересекает видимую часть карты, как аннотации, всегда выводятся на экран оверлейные программы, связанные с картой. В отличие от аннотаций, оверлейные программы масштабируются пропорционально с картой и поэтому автоматически не перекрывают друг друга. Это означает, что Вам придется, менее вероятно, удалить оверлейные программы и добавить их позже для предотвращения переполнения. В случаях, где ограничительные прямоугольники двух оверлейных программ действительно накладываются, можно или удалить одни из оверлейных программ или расположить их Z-порядок управлять, какой появляется на вершине.

overlays свойство MKMapView класс хранит зарегистрированные оверлейные программы в упорядоченном массиве. Порядок объектов в этом массиве соответствует Z-порядок объектов во время отображения с первым объектом в массиве, представляющем нижнюю часть Z-порядка. Для размещения наложения поверх всех других оверлейных программ Вы добавляете его до конца этого массива. Можно также вставить объекты в различных точках в массиве и обмениваться позицией двух объектов в массиве с помощью методов представления карты.

Если Вы решаете реализовать некоторый тип алгоритма обнаружения перекрытия для оверлейных программ, одно место, чтобы сделать так находится в mapView:didAddOverlayRenderers: метод Вашей карты просматривает делегата. Когда этот метод вызовут, используйте MKMapRectIntersectsRect функция, чтобы видеть, пересекает ли добавленное наложение границы каких-либо других оверлейных программ. Если существует перекрытие, используйте пользовательскую логику для выбора, какой должен быть помещен в вершину в дереве рендеринга и обмениваться их позициями по мере необходимости. (Логика сравнения может произойти на любом потоке, но потому что представление карты является интерфейсным элементом, любыми модификациями к overlays массив должен синхронизироваться и выполняться на основном потоке приложения.)

Используя оверлейные программы как аннотации

MKOverlay протокол соответствует MKAnnotation протокол. В результате все объекты наложения являются также объектами пометок и могут быть обработаны как один или оба в Вашем коде. Если Вы решили обработать объект наложения и как наложение и как аннотацию, Вы ответственны за управление тем объектом в двух местах. Если Вы хотите вывести на экран и средство рендеринга наложения и представление аннотации для объекта, необходимо реализовать обоих mapView:rendererForOverlay: и mapView:viewForAnnotation: методы в Вашем делегате приложения. Необходимо также добавить и удалить объект от обоих overlays и annotations массивы Вашей карты.