14

問題 注釈の周りにビジュアル半径の円を作成しようとしていますが、これは実際には固定サイズのままです。例えば。したがって、半径を 100m に設定すると、マップ ビューをズームアウトすると、半径の円が徐々に小さくなります。

スケーリングを達成できましたが、ユーザーがビューを操作すると、半径の四角形/円がピンの目印から「ジッター」しているように見えます。

これは、次期 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 setFrame:] に加えて [UIView setNeedsDisplay] を呼び出して、フレームが更新された後にビューが再描画されるようにするだけです。

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 );

}

ご協力いただきありがとうございます。ジョナサン

4

1 に答える 1

5

まず、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 を直接変更します。

    rect = [[self mapView] convertRegion:foo toRectToView: self.mapView];
    [[[self mapView] viewForAnnotation: annotation] setFrame:rect];
    
  2. の実装をdrawRect:に移動しLocationAnnotationViewます。

これは実装が簡単で、注釈ビューの中心点がピンとともに移動するため、問題に対処する必要があり、この問題は発生しません。

修正

コードには他に 2 つの問題があります。

  1. longitudeDelta を次のように設定します。

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

    メートルに変換された経度デルタは緯度によって変化するためです。または、緯度デルタのみを設定してから、rect を変更して長方形にすることもできます ( width==height)。

  2. では、渡された;drawRect:を使用しないでください。rect代わりに使用してself.frameください。これらが同じであるという保証はなく、rect何らかの値を持つ可能性があります。

これらが機能するかどうか教えてください;-)

于 2010-06-02T23:01:49.697 に答える