alt text http://www.gisnotes.com/wordpress/wp-content/uploads/2009/09/poly.png
简而言之,我试图弄清楚如何缩放在MKMapView(mapView)之上的自定义视图(geometryView)中实现的几何体(点,线和多边形)。
我做的是......
创建DrawMapViewController。在底部工具栏上添加UIBarButtonItems(MAP,PT,LN,PG)。
单击地图按钮后,您可以平移/缩放地图。这样可以通过设置geometryView.hidden = YES;
单击三个几何按钮中的任何一个时,geometryView会显示geometryView.hidden = NO,因此,启用touchEvents并从GeometryView.drawRect的方法中绘制几何图形。
图层排序如下:mapView位于geometryView的底部。
-geometryView
-mapView
我的问题是什么? 理想情况下,在“地图”模式下以及当用户进行平移和缩放时,我希望是否可以从geometryView显示绘图。但是当用户点击“map”时,geometryView.hidden = YES,因此绘图消失。如果我使geometryView可见,那么用户与geometryView交互而不是mapView,因此没有缩放和平移。
在显示自定义视图时,是否可以在自定义视图下方处理MKMapView的touchEvents(平移/缩放)?非常感谢任何其他想法/方法。
谢谢,
鲁珀特
GeometryView列表:
@synthesize mapview, pinFactory;
- (id)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
}
return self;
}
- (void)drawRect:(CGRect)rect {
// Drawing code
NSLog(@"DrawRect called");
CGContextRef context = UIGraphicsGetCurrentContext();
// Drawing lines with a white stroke color
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
// Draw them with a 2.0 stroke width so they are a bit more visible.
CGContextSetLineWidth(context, 2.0);
if(pinFactory.geometryState == 2){ //Draw Line
if( [pinFactory actualPinCount] > 1){
Pin *pin1 = (Pin *)[[pinFactory pinArray] objectAtIndex:0];
CGPoint pt1 = pin1.touchLocation;
CGContextMoveToPoint(context, pt1.x, pt1.y);
for (int i = 1; i < ([pinFactory actualPinCount]); i++)
{
Pin *pin2 = (Pin *)[[pinFactory pinArray] objectAtIndex:i];
CGPoint pt2 = pin2.touchLocation;
CGContextAddLineToPoint(context, pt2.x, pt2.y);
}
CGContextStrokePath(context);
}
}
else if(pinFactory.geometryState == 3){ //Draw Polygon
//if there are two points, draw a line first.
//if there are three points, fill the polygon
if( [pinFactory actualPinCount] == 2){
Pin *pin1 = (Pin *)[[pinFactory pinArray] objectAtIndex:0];
CGPoint pt1 = pin1.touchLocation;
CGContextMoveToPoint(context, pt1.x, pt1.y);
Pin *pin2 = (Pin *)[[pinFactory pinArray] objectAtIndex:1];
CGPoint pt2 = pin2.touchLocation;
CGContextAddLineToPoint(context, pt2.x, pt2.y);
CGContextStrokePath(context);
}
else if([pinFactory actualPinCount] > 2){
//fill with a blue color
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1.0);
Pin *pin1 = (Pin *)[[pinFactory pinArray] objectAtIndex:0];
CGPoint pt1 = pin1.touchLocation;
CGContextMoveToPoint(context, pt1.x, pt1.y);
for (int i = 1; i < ([pinFactory actualPinCount]); i++)
{
Pin *pin2 = (Pin *)[[pinFactory pinArray] objectAtIndex:i];
CGPoint pt2 = pin2.touchLocation;
CGContextAddLineToPoint(context, pt2.x, pt2.y);
}
CGContextClosePath(context);
CGContextDrawPath(context, kCGPathFillStroke);
}
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self setNeedsDisplay];
UITouch* aTouch = [touches anyObject];
location = [aTouch locationInView:self];
NSLog(@"touchesBegan: x:%f, y:%f", location.x, location.y );
CLLocationCoordinate2D coordinate = [mapview convertPoint:location toCoordinateFromView:self];
switch (pinFactory.geometryState) {
case 1:{
if( [pinFactory actualPinCount] == 1){
//[UIView beginAnimations:@"stalk" context:nil];
//[UIView setAnimationDuration:1];
//[UIView setAnimationBeginsFromCurrentState:YES];
Pin *pin = (Pin *)[pinFactory getObjectAtIndex:0];
[mapview removeAnnotation:pin];
[pinFactory removeObject:pin];
Pin *newPin = [[Pin alloc] initWithCoordinate:coordinate initLocation:location withTitle:@"My Pin"];
[pinFactory addObject:newPin];
[mapview addAnnotation:newPin];
[newPin release];
//[UIView commitAnimations];
}
else{
//Lets add a new pin to the geometry
Pin *pin = [[Pin alloc] initWithCoordinate:coordinate initLocation:location withTitle:@"My Pin"];
[pinFactory addObject:pin];
[mapview addAnnotation:pin];
[pin release];
}
break;
}
case 2:{
//Lets add a new pin
Pin *pin = [[Pin alloc] initWithCoordinate:coordinate initLocation:location withTitle:@"My Pin"];
[pinFactory addObject:pin];
[mapview addAnnotation:pin];
[pin release];
[self setNeedsDisplay];
break;
}
case 3:{
//Lets add a new pin
Pin *pin = [[Pin alloc] initWithCoordinate:coordinate initLocation:location withTitle:@"My Pin"];
[pinFactory addObject:pin];
[mapview addAnnotation:pin];
[pin release];
[self setNeedsDisplay];
break;
}
default:
break;
}
}
- (void)dealloc {
[super dealloc];
}
@end
DrawMapViewController清单:
#import "DrawMapViewController.h"
#import "Pin.h"
@implementation DrawMapViewController
@synthesize mapview, mapBarButton, pointBarButton, lineBarButton, polygonBarButton, geometryView;
/* State represents state of the map
* 0 = map
* 1 = point
* 2 = line
* 3 = polygon
*/
// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Custom initialization
self.title = @"Map";
}
return self;
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
mapview.mapType = MKMapTypeSatellite;
NSMutableArray *pinArray = [[NSMutableArray alloc] initWithObjects:nil];
pinFactory = [[PinFactory alloc] initWithArray:pinArray];
pinFactory.map = mapview;
[pinArray release];
geometryView = [[GeometryView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 372.0f)];
geometryView.pinFactory = pinFactory;
geometryView.mapview = mapview;
geometryView.backgroundColor = [UIColor clearColor];
[self.view addSubview:geometryView];
[self changeButtonAndViewState:0];
}
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[mapBarButton release];
[pointBarButton release];
[lineBarButton release];
[polygonBarButton release];
[super dealloc];
}
- (IBAction)mapBarButtonPressed{
NSLog(@"mapBarButtonPressed");
[self changeButtonAndViewState:0];
}
- (IBAction)pointBarButtonPressed{
NSLog(@"pointBarButtonPressed");
[self changeButtonAndViewState:1];
if( [pinFactory actualPinCount] > 0){
[self resetGeometry];
}
}
- (IBAction)lineBarButtonPressed{
NSLog(@"lineBarButtonPressed");
if( [pinFactory actualPinCount] > 0){
[self resetGeometry];
}
[self changeButtonAndViewState:2];
}
- (IBAction)polygonBarButtonPressed{
NSLog(@"polygonBarButtonPressed");
if( [pinFactory actualPinCount] > 0){
[self resetGeometry];
}
[self changeButtonAndViewState:3];
}
- (void)resetGeometry{
NSLog(@"resetting geometry.. deleting all pins");
[mapview removeAnnotations:[pinFactory pinArray]];
NSMutableArray *array = [pinFactory pinArray];
[array removeAllObjects];
[geometryView setNeedsDisplay];
}
- (void)changeButtonAndViewState:(int)s{
[pinFactory setGeometryState:s];
mapBarButton.style = UIBarButtonItemStyleBordered;
pointBarButton.style = UIBarButtonItemStyleBordered;
lineBarButton.style = UIBarButtonItemStyleBordered;
polygonBarButton.style = UIBarButtonItemStyleBordered;
pointBarButton.enabled = YES;
lineBarButton.enabled = YES;
polygonBarButton.enabled = YES;
switch ([pinFactory geometryState]) {
case 0:{
mapBarButton.style = UIBarButtonItemStyleDone;
geometryView.hidden = YES;
break;
}
case 1:{
pointBarButton.enabled = NO;
pointBarButton.style = UIBarButtonItemStyleDone;
geometryView.hidden = NO;
break;
}
case 2:{
lineBarButton.enabled = NO;
lineBarButton.style = UIBarButtonItemStyleDone;
geometryView.hidden = NO;
break;
}
case 3:{
polygonBarButton.enabled = NO;
polygonBarButton.style = UIBarButtonItemStyleDone;
geometryView.hidden = NO;
break;
}
default:
break;
}
}
-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animate{
NSLog(@"regionDidChangeAnimated");
}
@end
答案 0 :(得分:1)
嘿,我看到没有人回答过你,我只知道如何做到这一点。不幸的是,你不能拦截事件并将它们转发到mapView,所以像
@interface MapOverlay
MKMapView* map;
@end
@implementation
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// Do my stuff
foo();
bar();
// Forward to the map
[map touchesBegan....];
}
@end
这是你想要做的但是它不起作用。由于某种原因,你不能拦截地图的事件,也不能反向和子类化MKMapView并重载它的触摸方法。我发现这样做的唯一方法如下。
创建MapOverlay视图,将其设置为具有透明背景并禁用触摸。在MKMapView上叠加它。然后执行以下操作
子类UIWindow带有一个自定义类,可以将所有触摸转发到叠加层,或者将逻辑处理为“如果叠加层未隐藏,然后转发”,或者在叠加层本身保持状态。无论如何它看起来像这样
@implementation CustomWindow
- (void)sendEvent:(UIEvent*)event
{
[super sendEvent:event];
// Forward the event to the overlay
}
当您将事件转发到叠加层时,首先检查触摸是否在mapView区域内,然后找出它们的触摸类型,然后在叠加层上调用正确的触摸方法。
祝你好运!答案 1 :(得分:0)
我知道这个答案可能来得太晚了,但无论如何我会为了那些也遇到过这个问题的人(比如我自己)的利益而采取刺激。
MKMapView类的触摸事件都由内部的UIScrollView处理。您可以通过将MKMapView作为自定义UIView的子视图,并在自定义视图中提供自定义触摸方法来捕获此滚动视图的事件。
诀窍是跟踪MKMapView使用的UIScrollView。为此,我重写了“hitTest”方法,该方法返回“self”,我相信这意味着这个自定义视图应该处理触摸事件。
此外,hitTest方法获取MKMapView的UIScrollView。在我的自定义UIView中,我将其称为“echo_to”,因为事件随后被回显到UIScrollView以使地图正常工作。
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
// Get the UIView (in this case, a UIScrollView) that
// would ordinarily handle the events
echo_to = [super hitTest:point withEvent:event];
// But let it be known we'll handle them instead.
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@"Touches Began");
// add your custom annotation behavior here
[echo_to touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@"Touches moved");
// add your custom annotation behavior here
[echo_to touchesMoved:touches withEvent:event];
}
祝你好运。
答案 2 :(得分:0)
根据geometryView的复杂程度,您可以使用注释视图来绘制它。
这种方法的缺点是视图不会随地图缩放(尽管您可以使用mapView:regionDidChangeanimated:
委托方法在缩放后重绘),但它会平移地图。
答案 3 :(得分:0)
只要您不需要用户点击注释或捏合缩放地图,hotTest技巧就会很有效。这些都不能转发。