Масштабирование аннотаций MKMapView относительно уровня масштабирования
Проблема
Я пытаюсь создать окружность визуального радиуса вокруг аннотации, которая остается в фиксированном размере в реальном выражении. Например. Поэтому, если я задаю радиус до 100 м, по мере того, как вы уменьшаете масштаб из вида карты, круг радиуса становится все меньше.
Мне удалось достичь масштабирования, однако радиус rect/circle кажется "Jitter" подальше от метки метки, поскольку пользователь манипулирует просмотром.
Мне повезло, что этого намного легче достичь на предстоящей 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];
}
}
}
Объект Annotation (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 для рисования полупрозрачных окружностей. setFrame также перегружен в этом подклассе UIView, но он служит только для вызова [UIView setNeedsDisplay] в дополнение к [UIView setFrame:], чтобы гарантировать, что представление будет перерисовано после обновления фрейма.
Объект radiusView (CircleView) метод drawRect выглядит следующим образом
-(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 );
}
Спасибо за подшипник со мной, любая помощь приветствуется.
Джонатан
Ответы
Ответ 1
Во-первых, что foo
используется в первой функции? И я предполагаю, что radiusView
parent - это аннотация, верно?
"Jittering"
Кроме того, центральная точка radiusView
должна совпадать с центральной точкой аннотацииView. Это должно решить вашу проблему:
-(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];
- При рисовании эллипса не используйте
rect
, переданный в drawRect:
, он не должен совпадать с кадром. Безопаснее напрямую использовать self.frame
Ненужное представление
Теперь я дал вышеприведенные моменты, если вам нужно использовать вышеупомянутую иерархию, но я не понимаю, почему бы вам просто не нарисовать свои эллипсы непосредственно в LocationAnnotationView
? Это там для этого в конце концов. Вот как вы это делаете:
-
при масштабировании напрямую меняйте прямой аннотацииView:
rect = [[self mapView] convertRegion:foo toRectToView: self.mapView];
[[[self mapView] viewForAnnotation: annotation] setFrame:rect];
-
Переместите реализацию drawRect:
в LocationAnnotationView
.
Это проще реализовать и должно решить вашу проблему, поскольку центральная точка представления аннотаций перемещается с помощью вашего булавки, и вы не должны видеть эту проблему.
затруднительный
В коде есть еще две проблемы:
-
Установите longitudeDelta следующим образом:
region.span.longitudeDelta = 0.002*cos(region.center.latitude*pi/180.0);
поскольку дельта долготы, преобразованная в метры, изменяется с широтой. В качестве альтернативы вы можете установить только делит широту, затем изменить прямоугольник, чтобы он стал прямоугольным (width==height
).
-
в drawRect:
, не используйте пройденный rect
; вместо этого используйте self.frame
. Там нет гарантии, что они будут одинаковыми, а rect
может иметь любую ценность.
Сообщите мне, если это работает; -)