Масштабирование Аннотации MKMapView относительно уровня масштабирования - PullRequest
14 голосов
/ 22 мая 2010

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

Я смог добиться масштабирования, однако радиус прямоугольника / круга кажется "дрожащим""Вдали от метки Pin, когда пользователь манипулирует видом.

Я уверен, что этого будет гораздо проще добиться в следующей версии iPhone OS 4, однако мое приложение должно поддерживать 3.0.

Проявление Вот видео поведения.

Реализация Аннотации добавляются в Mapview обычным способом,и я использовал метод делегата в моем подклассе UIViewController ( MapViewController ), чтобы увидеть, когда регион изменяется.

-(void)mapView:(MKMapView *)pMapView regionDidChangeAnimated:(BOOL)animated{

//Get the map view
MKCoordinateRegion region;
CGRect rect;

//Scale the annotations
for( id<MKAnnotation> annotation in [[self mapView] annotations] ){

    if( [annotation isKindOfClass: [Location class]] && [annotation conformsToProtocol:@protocol(MKAnnotation)] ){
        //Approximately 200 m radius
        region.span.latitudeDelta = 0.002f;
        region.span.longitudeDelta = 0.002f;

        region.center = [annotation coordinate];

        rect = [[self mapView] convertRegion:region toRectToView: self.mapView];

        if( [[[self mapView] viewForAnnotation: annotation] respondsToSelector:@selector(setRadiusFrame:)] ){

            [[[self mapView] viewForAnnotation: annotation] setRadiusFrame:rect];

        }

    }

}

Объект аннотации ( LocationAnnotationView )подкласс MKAnnotationView и его setRadiusFrame выглядит следующим образом

-(void) setRadiusFrame:(CGRect) rect{

CGPoint centerPoint;

//Invert
centerPoint.x = (rect.size.width/2) * -1;
centerPoint.y = 0 + 55 + ((rect.size.height/2) * -1);

rect.origin = centerPoint;

[self.radiusView setFrame:rect];
}

И, наконец, объект radiusView является подклассом UIView, который переопределяет drawRect mметод рисования полупрозрачных кругов.setFrame также перегружен в этом подклассе UIView, но он служит только для вызова [UIView setNeedsDisplay] в дополнение к [UIView setFrame:], чтобы гарантировать, что представление перерисовывается после обновления кадра.

radiusViewМетод drawRect объекта ( CircleView ) выглядит следующим образом

-(void) drawRect:(CGRect)rect{

//NSLog(@"[CircleView drawRect]");

[self setBackgroundColor:[UIColor clearColor]];
//Declarations
CGContextRef context;
CGMutablePathRef path;

//Assignments
context = UIGraphicsGetCurrentContext();

path = CGPathCreateMutable();

//Alter the rect so the circle isn't cliped

//Calculate the biggest size circle
if( rect.size.height > rect.size.width ){
    rect.size.height = rect.size.width;
}
else if( rect.size.height < rect.size.width ){
    rect.size.width = rect.size.height;
}

rect.size.height -= 4;
rect.size.width  -= 4;
rect.origin.x += 2;
rect.origin.y += 2;

//Create paths
CGPathAddEllipseInRect(path, NULL, rect );

//Create colors
[[self areaColor] setFill];

CGContextAddPath( context, path);
CGContextFillPath( context );

[[self borderColor] setStroke];

CGContextSetLineWidth( context, 2.0f );
CGContextSetLineCap(context, kCGLineCapSquare);
CGContextAddPath(context, path );
CGContextStrokePath( context );
CGPathRelease( path );

//CGContextRestoreGState( context );

}

Спасибо за помощь, любая помощь приветствуется.Jonathan

1 Ответ

5 голосов
/ 03 июня 2010

Во-первых, что foo используется в первой функции? И я предполагаю, что родительский элемент radiusView является представлением аннотации, верно?

"Дрожание"

Кроме того, центральная точка radiusView должна совпадать с точкой обзора annotationView. Это должно решить вашу проблему:

-(void) setRadiusFrame:(CGRect)rect{
    rect.origin.x -= 0.5*(self.frame.size.width - rect.size.width);
    rect.origin.y -= 0.5*(self.frame.size.height - rect.size.height);
    [self.radiusView setFrame:rect]
}

Ненужный метод

Вы можете установить кадр непосредственно на radiusView и избежать вышеуказанного расчета:

    UIView * radiusView = [[[self mapView] viewForAnnotation: annotation] radiusView];
    rect = [[self mapView] convertRegion:foo toRectToView: radiusView.superView];
    [radiusView setFrame:rect];
  1. При рисовании эллипса не используйте rect, переданный drawRect:, он не должен совпадать с рамкой. Безопаснее напрямую использовать self.frame

Ненужный вид

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

  1. при масштабировании измените прямоугольник annotationView напрямую:

    rect = [[self mapView] convertRegion:foo toRectToView: self.mapView];
    [[[self mapView] viewForAnnotation: annotation] setFrame:rect];
    
  2. Переместить реализацию drawRect: в LocationAnnotationView.

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

Исправления

В коде есть еще две проблемы:

  1. Установить долготуДельта так:

    region.span.longitudeDelta = 0.002*cos(region.center.latitude*pi/180.0);
    

    , поскольку дельта долготы, преобразованная в метры, изменяется в зависимости от широты. Кроме того, вы можете установить только дельту широты, а затем изменить прямоугольник, чтобы он стал прямоугольным (width==height).

  2. в drawRect:, не используйте переданный rect; вместо этого используйте self.frame. Нет гарантии, что они одинаковы, и rect может иметь любое значение.

Дайте мне знать, если это работает; -)

...