1

替代文字 http://www.gisnotes.com/wordpress/wp-content/uploads/2009/09/poly.png

简而言之,我试图弄清楚如何缩放在 MKMapView (mapView) 之上的自定义视图 (geometryView) 中实现的几何图形(点、线和多边形)。

我所做的是..

  1. 创建 DrawMapViewController。在底部工具栏上添加 UIBarButtonItems(MAP、PT、LN、PG)。

  2. 当您单击地图按钮时,您可以在地图上平移/缩放。这通过设置geometryView.hidden = YES来启用mapView;

  3. 当单击三个几何按钮中的任何一个时,geometryView 将通过geometryView.hidden = NO 显示,从而启用touchEvents 并从GeometryView.drawRect 的方法中绘制几何。

图层顺序如下:mapView 在geometryView 的底部。

-几何视图

-mapView

我的问题是什么? 理想情况下,在“地图”模式期间以及当用户平移和缩放时,我希望它是否可以显示来自 geometryView 的绘图。但是当用户点击“地图”时,geometryView.hidden = YES,因此绘图消失了。如果我让geometryView 可见,那么用户与geometryView 交互而不是mapView,因此没有缩放和平移。

显示自定义视图时,是否可以在自定义视图下方处理 MKMapView 的 touchEvents(平移/缩放)?非常感谢任何其他想法/方法。

谢谢,

鲁珀特

几何视图列表:

@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
4

4 回答 4

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 区域内,然后确定它们是什么类型的触摸,然后在叠加层上调用正确的触摸方法。

祝你好运!

于 2009-11-07T23:40:27.507 回答
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];
}

祝你好运。

于 2009-12-29T22:58:31.020 回答
0

根据几何视图的复杂程度,您可以使用注释视图来绘制它。

这种方法的缺点是视图不会随地图缩放(尽管您可以使用mapView:regionDidChangeanimated:委托方法在缩放后重绘),但它会随地图平移。

于 2009-12-29T23:02:07.193 回答
0

只要您不需要用户能够点击注释或捏合和缩放地图,hitTest 技巧就很有效。这些都不能转发。

于 2010-06-02T21:04:21.243 回答