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. 3つのジオメトリボタンのいずれかがクリックされると、geometryViewはgeometryView.hidden = NOで表示されるため、touchEventsが有効になり、GeometryView.drawRectのメソッドからジオメトリが描画されます。

レイヤーの順序は次のとおりです。mapViewはgeometryViewの下部にあります。

-geometryView

-mapView

私の問題は何ですか? 理想的には、「マップ」モード中、およびユーザーがパンおよびズームしているときに、geometryViewから図面を表示できるかどうかを期待しています。ただし、ユーザーが「マップ」を押すと、geometryView.hidden = YESになるため、描画が消えます。GeometryViewを表示すると、ユーザーはmapViewではなくgeometryViewを操作するため、ズームやパンは行われません。

カスタムビューが表示されているときに、カスタムビューの下にある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
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

洗練されたgeometryViewによっては、注釈ビューを使用して描画できる場合があります。

このアプローチの欠点は、ビューがマップに合わせて拡大縮小されないことです(ただし、mapView:regionDidChangeanimated:デリゲートメソッドを使用してズーム後に再描画できます)が、マップに合わせてパンします。

于 2009-12-29T23:02:07.193 に答える
0

この答えはおそらく遅すぎることはわかっていますが、この問題に遭遇したことのある人(私自身など)のために、とにかく突き刺します.

MKMapView クラスのタッチ イベントはすべて、内部で UIScrollView によって処理されます。このスクロール ビューのイベントをキャプチャするには、MKMapView をカスタム UIView のサブビューにし、カスタム ビューでカスタム タッチ メソッドを提供します。

トリックは、MKMapView によって使用される UIScrollView を追跡することです。これを行うために、「self」を返す「hitTest」メソッドをオーバーライドしました。これは、このカスタム ビューがタッチ イベントを処理する必要があることを意味すると考えています。

また、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

hitTest トリックは、ユーザーが注釈をタップしたり、マップをピンチ アンド ズームしたりできるようにする必要がない限り、うまく機能します。これらはいずれも転送できません。

于 2010-06-02T21:04:21.243 に答える