Як активувати вигляд виноски MKAnnotationView, не торкаючись штифта?


75

Я працюю над MKMapViewзвичайним кольоровим штифтом як місце розташування. Я хотів би мати можливість показу виноски, не торкаючись шпильки.

Як мені це зробити? Виклик setSelected:YESанотації не дав результату. Я думаю про імітацію дотику до шпильки, але я не знаю, як це зробити.


Моє рішення в іншому питанні: stackoverflow.com/a/13026353/736384
Луїс Ascorbe

Відповіді:


63

Але є проблема, щоб отримати рішення benvolioT для роботи - код

for (id<MKAnnotation> currentAnnotation in mapView.annotations) {       
    if ([currentAnnotation isEqual:annotationToSelect]) {
        [mapView selectAnnotation:currentAnnotation animated:FALSE];
    }
}

слід дзвонити з - (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView, і нікуди більше.

Послідовність , в якій різні методи , такі як viewWillAppear, viewDidAppearз UIViewControllerі - (void)mapViewDidFinishLoadingMap:(MKMapView *)mapViewназивається відрізняється між першим часом карта завантажується з одного конкретного місця розташування і наступні моменти часу карта відображається з тією ж адресою. Це трохи хитро.


4
Нічого хитрого. Просто потрібно було знати, щоб зателефонувати: [mapView selectAnnotation], а не [annotation setSelected]. Дякую!
Бентфорд,

Гаразд, це спрацювало вперше автоматично. Але зараз це вже не працює? що за? - (void) mapViewDidFinishLoadingMap: (MKMapView *) _ mapView {[mapView selectAnnotation: addAnnotation animated: YES]; }
fulvio

4
mapViewDidFinishLoadingMap запускається лише вперше, оскільки карти кешуються. Коли карта завантажується з кешу, mapViewDidFinishloadingMap більше не запускається.
Niels R.,

8
Правильним методом делегування, який гарантує, що ваш вид анотацій готовий до відображення виноски, є той, який вказав @ user507778. mapView:didAddAnnotationViews:. Це гарантує завантаження подання карти, а також подання анотацій та готовність до відображення спливаючої виноски. Будь-який інший спосіб може працювати чи ні, залежно від швидкості з'єднання, системи кешування, перебоїв програми тощо.
Леандро Алвес

1
@LeandroAlves Це правильне рішення. Дякую. Кореневу відповідь проголосували з тієї самої причини, яку ви описали.
Алекс Н.

34

Гаразд, ось рішення цієї проблеми.

Для відображення використовуйте виноски MKMapView«s selectAnnotation:animatedметод.


3
Це не допомагає. Я можу це зателефонувати, і це не завжди оживить вибір. Перший раз, так. Кожного разу після цього ні - навіть якщо метод викликаний. Рішення benvolioT також не працює для мене. Навіть якщо я викликаю selectAnnotation: animated: безпосередньо, коли анотація відома, не працює. Ті самі проблеми, що й раніше. :(
Джо Д'Андреа 02

@Joe Я вважаю, що ви повинні видалити анотацію перед викликом, щоб анімація відображалася.
О, Денні Бой,

коментуючи, що якщо штифт знаходиться у вибраному стані, і ви вибрали його знову, він залишається в тому ж вибраному стані. доки ви не знімете його або користувач не скасує вибір.
dklt

32

Припускаючи, що ви хочете, щоб було вибрано останнє подання анотації, ви можете розмістити код нижче:

[mapView selectAnnotation:[[mapView annotations] lastObject] animated:YES];

у представнику нижче:

- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views
{
    //Here
    [mapView selectAnnotation:[[mapView annotations] lastObject] animated:YES];
}

Це було б рішення, яке спрацювало для мене! дуже дякую!
Торан Біллапс

1
Обережно! Цей метод делегування викликається для анотацій, які в даний час видно, тобто тих, що знаходяться в межах області карти, яка наразі відображається на екрані.
Луїс Аскорбе

21

Гаразд, для успішного додавання виноски потрібно зателефонувати selectAnnotation: animated після того, як були додані всі подання анотацій, використовуючи didAddAnnotationViews делегата:

- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views{
    for (id<MKAnnotation> currentAnnotation in mapView.annotations) {       
        if ([currentAnnotation isEqual: annotationToSelect]) {
            [mapView selectAnnotation:currentAnnotation animated:YES];
        }
    }
}

Я виявив, що це найкращий спосіб зробити це, оскільки цей метод буде запущений при додаванні анотації.
Гевін,

1
Цей метод видаляє виноску разом із шпилькою, чи є рішення, яке може показати виноску відразу після того, як штифт буде скинуто на карту?
Майкл

12

Спробувавши різноманітні відповіді на цю тему, я нарешті придумав це. Це працює дуже надійно, я ще не бачив, щоб він провалився:

- (void)mapView:(MKMapView *)aMapView didAddAnnotationViews:(NSArray *)views;
{
    for(id<MKAnnotation> currentAnnotation in aMapView.annotations) 
    {       
        if([currentAnnotation isEqual:annotationToSelect]) 
        {
            NSLog(@"Yay!");
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.3 * NSEC_PER_SEC), dispatch_get_current_queue(), ^
            {
                [aMapView selectAnnotation:currentAnnotation animated:YES];
            });
        }
    }
}

Блок використовується для невеликої затримки, оскільки без нього виноска може відображатися неправильно.


2
Неймовірно. Це такий клубок, і він у перегоновому стані, але це працює. Тут вражає те, що з тим, що раскадровка робить в основному все, не очевидно, що делегата потрібно підключити до розкадровки - якщо ви не торкалися MKMapViews протягом 3 місяців. Це те, що розкадровка повинна робити автоматично або, принаймні, попереджати вас. Я волів би визначити посилання mapKit на init І делегата на init, аніж розкадровку виконати 1/2 роботи та залишити вас повішеним, не знаючи, що залишилося виконати ще 1/2 роботи. > 1 год витрачено на це.
Alex Zavatone

Це чудово працює, щоб показати виноску відразу після завершення падіння шпильки. Без затримки ви бачите, що виноска падає разом із шпилькою, що виглядає химерно. Прикро, що "didAddAnnotationViews" викликається в той момент, коли штифт починає падати, а не в той момент, коли він приземляється.
James Toomey

9

Для мене це не працює. Я підозрюю помилку в API MapKit.

Перегляньте це посилання, щоб дізнатися більше про когось іншого, хто не працює: http://www.iphonedevsdk.com/forum/iphone-sdk-development/19740-trigger-mkannotationview-callout-bubble.html#post110447

--edit--

Гаразд, після того, як якийсь час викрутив це, ось що я зміг змусити працювати:

for (id<MKAnnotation> currentAnnotation in mapView.annotations) {       
    if ([currentAnnotation isEqual:annotationToSelect]) {
        [mapView selectAnnotation:currentAnnotation animated:FALSE];
    }
}

Зверніть увагу, що для цього потрібна реалізація - (BOOL)isEqual:(id)anObjectдля вашого класу, який реалізує протокол MKAnnotation.


на основі цього я отримав [mapView selectAnnotation: [mapView.annotations objectAtIndex: 0] animated: false]; для роботи, щоб вибрати першу анотацію.
Andiih

6

Якщо ви просто хочете відкрити виноску для останньої доданої анотації, спробуйте це, це працює для мене.

[mapView selectAnnotation:[[mapView annotations] lastObject] animated:YES];


6

Проблема із дзвінком selectAnnotationз- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView полягає в тому, що, як випливає з назви, ця подія запускається лише після того, як ваш MapView завантажується спочатку, тому ви не зможете активувати додаткову інформацію анотації, якщо ви додасте її після завершення завантаження MapView.

Проблема із його викликом - (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)viewsполягає в тому, що ваша анотація може не відображатися на екрані при виклику , що не selectAnnotationпризведе до її ефекту. Навіть якщо ви відцентруєте область MapView до координати анотації перед додаванням анотації, невеликої затримки, необхідної для встановлення області MapView, достатньо, selectAnnotationщоб її було викликано до того, як анотація з’явиться на екрані, особливо якщо ви анімуєте setRegion.

Деякі люди вирішили цю проблему, зателефонувавши selectAnnotationпісля затримки:

-(void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
    [self performSelector:@selector(selectLastAnnotation)
        withObject:nil afterDelay:1];
}

-(void)selectLastAnnotation {
    [myMapView selectAnnotation:
        [[myMapView annotations] lastObject] animated:YES];
}

Але навіть тоді ви можете отримати дивні результати, оскільки може знадобитися більше однієї секунди, щоб анотація з’явилася на екрані, залежно від різних факторів, таких як відстань між попереднім регіоном MapView та новим, або швидкістю підключення до Інтернету.

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animatedНатомість я вирішив здійснити виклик, оскільки він гарантує, що анотація насправді знаходиться на екрані (за умови, що ви встановили для регіону MapView координату анотації), оскільки ця подія запускається після завершення setRegion (та його анімації). Однак regionDidChangeAnimatedспрацьовує щоразу, коли регіон вашого MapView змінюється, зокрема, коли користувач просто прокручує карту, тому вам потрібно переконатися, що у вас є умова, щоб правильно визначити, коли саме час для запуску додаткової виноски анотації.

Ось як я це зробив:

MKPointAnnotation *myAnnotationWithCallout;

- (void)someMethod {
    MKPointAnnotation *myAnnotation = [[MKPointAnnotation alloc] init];
    [myAnnotation setCoordinate: someCoordinate];
    [myAnnotation setTitle: someTitle];

    MKCoordinateRegion someRegion =
       MKCoordinateRegionMakeWithDistance (someCoordinate, zoomLevel, zoomLevel);

    myAnnotationWithCallout = myAnnotation;
    [myMapView setRegion: someRegion animated: YES];
    [myMapView addAnnotation: myAnnotation];
}

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
    if (myAnnotationWithCallout)
    {
        [mapView selectAnnotation: myAnnotationWithCallout animated:YES];
        myAnnotationWithCallout = nil;
    }
}

Таким чином ваша анотація гарантовано відображатиметься на екрані в той момент, коли selectAnnotationбуде викликано, а if (myAnnotationWithCallout)частина гарантує, що жодна установка регіону, крім тієї, що - (void)someMethodбуде, не ініціюватиме додаткову інформацію.


5

Я уважно прочитав API і нарешті виявив проблему:


Якщо вказана анотація відсутня на екрані і, отже, не має пов'язаного подання анотацій, цей метод не впливає.

Таким чином, ви можете почекати деякий час (наприклад, 3 секунди), а потім виконати цю дію. Тоді це працює.


1
Це створює перегонові умови. Чи немає події, яка вказує на те, що на карті закінчився показ, яку ви можете використати для активації відображення?
Alex Zavatone

3

Через щось на зразок коду, показаного benvolioT, який, як я підозрюю, існує в системі, коли я використовував метод selectAnnotation: animation:, він не відображав callOut, я здогадався, що причина в тому, що його вже було вибрано, і він уникав від просячи MapView перемалювати callOut на карті, використовуючи заголовок анотації та підзаголовок.

Отже, рішення полягало в тому, щоб спочатку скасувати вибір і повторно вибрати його.

Напр .: По-перше, мені потрібно було зробити це за допомогою методу Apple touchMoved (тобто як перетягнути AnnotationView), щоб приховати callOut. (Просто використання annotation.canShowAnnotation = НІ один не працює, оскільки я підозрюю, що він потребує перемальовування. DeselectAnnotaiton викликає необхідні дії. Крім того, скасування виділення самостійно не зробило цього фокусу, callOut зник лише один раз і перемальовувався відразу. Це було натяком на те, що його було вибрано автоматично).

annotationView.canShowAnnotation = NO;
[mapView deselectAnnotation:annotation animated:YES];

Тоді просто використання коду нижче методу touchEnded не повернуло callOut (Анотація була автоматично вибрана системою на той час, і, мабуть, перемальовування callOut ніколи не відбувається):

annotationView.canShowAnnotation = YES;
[mapView selectAnnotation:annotation animated:YES];

Рішенням було:

annotationView.canShowAnnotation = YES;
[mapView deselectAnnotation:annotation animated:YES];
[mapView selectAnnotation:annotation animated:YES];

Це просто викупило callOut, імовірно, воно знову ініціювало процес перемальовування callOut за допомогою mapView.

Строго кажучи, я повинен визначити, чи є анотація поточною анотацією чи ні (вибрано, що я знаю, що це таке) і чи відображається callOut насправді чи ні (чого я не знаю), і прийняти рішення перемалювати його відповідно, що б бути краще. Однак я ще не знайшов методу виявлення callOut, а намагання зробити це на цьому етапі трохи непотрібне.


1

Відповідь Стіва Ши дав мені зрозуміти, що selectAnnotation потрібно викликати з методу mapViewDidFinishLoadingMap. На жаль, я не можу проголосувати, але я хочу тут подякувати.



-1

Скидання анотацій також призведе до додаткової інформації.

    [mapView removeAnnotation: currentMarker];
    [mapView addAnnotation:currentMarker];
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.