MKMapView地圖相關(guān)問題總結(jié)

前段時(shí)間,在項(xiàng)目上做了一些地圖相關(guān)的功能,解決了三個(gè)特殊需求,在此總結(jié)一下,以備日后使用:

1. MKOverlayView的拖動實(shí)現(xiàn);
2. 大頭針pin 的拖動實(shí)現(xiàn);
3. 隨地圖的縮放而縮放的焦點(diǎn)框功能實(shí)現(xiàn);


1. MKOverlayView的拖動實(shí)現(xiàn)

首先,直接給MKOverlayView視圖本身添加一個(gè)拖動手勢是不可行的,因?yàn)镸KOverlayView不是通過簡單的addSubview:添加到地圖圖層上的。

MKOverlayView視圖的現(xiàn)實(shí)過程:
1.1 使用MKPolygon的addOverlay:方法來添加OverlayView數(shù)據(jù)
源overlay,其中包括了圖層的經(jīng)緯度坐標(biāo)數(shù)據(jù)。

CLLocationCoordinate2D leftUp = CLLocationCoordinate2DMake(center.latitude - gap, center.longitude - gap);
CLLocationCoordinate2D rightUp = CLLocationCoordinate2DMake(center.latitude + gap, center.longitude - gap);
CLLocationCoordinate2D leftDown = CLLocationCoordinate2DMake(center.latitude - gap, center.longitude + gap);
CLLocationCoordinate2D rightDown = CLLocationCoordinate2DMake(center.latitude + gap, center.longitude + gap);
            
CLLocationCoordinate2D coordinates[4] = {leftUp, leftDown, rightUp, rightDown};
MKPolygon *polygon = [MKPolygon polygonWithCoordinates:coordinates count:4];
[m_MapView addOverlay:polygon];

1.2 然后再實(shí)現(xiàn)MKMapView的代理方法:

-(MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay
{
    MKOverlayView *pview = [[MKOverlayView alloc] initWithOverlay:overlay];
    pview.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:0.4f];    

    return pview;
}```

這樣就會給地圖的圖層中嵌入一個(gè)指定位置和大小的視圖,效果上是與地圖合為一體的,可以一起移動和縮放,

也就是說通過`addOverlay: `來添加視圖的數(shù)據(jù)源,然后在

-(MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay```

方法中去繪制視圖本身(圖層顏色,也可以繪制文字在上面)。

MKOverlayView的類型參數(shù)有以下幾種:

數(shù)據(jù)類 對應(yīng)view 說明
MKPolygon MKOverlayView 矩形
MKCircle MKCircleView 圓形
MKPolyline MKPolylineView 線條

那如何拖動MKOverlayView呢?

- (CGPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate toPointToView:(nullable UIView *)view

使用上述方法將MKOverlayView的經(jīng)緯度坐標(biāo)轉(zhuǎn)化為相對于MKMapView的點(diǎn)坐標(biāo),然后在同樣的位置加上一個(gè)同樣大小的透明子視圖,給自視圖添加拖動手勢UIPanGestureRecognizer,每次拖動的時(shí)候先使用removeOverlay:刪除之前的MKOverlayView,然后再重新以拖動點(diǎn)為中心,加載新的MKOverlayView即可,效果很良好,不會出現(xiàn)閃爍的現(xiàn)象。
由于地圖本身可以放大,縮小,移動,所以在這些操作之后也需要調(diào)整這個(gè)子視圖的大小:

//當(dāng)拖拽,放大,縮小,雙擊手勢開始時(shí)調(diào)用
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
//當(dāng)拖拽,放大,縮小,雙擊手勢結(jié)束時(shí)調(diào)用
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated

2. 大頭針pin 的拖動實(shí)現(xiàn);

拖動大頭針的方法系統(tǒng)API有提供:

  • 新建一個(gè)繼承<MKAnnotation>協(xié)議的大頭針數(shù)據(jù)類,并添加坐標(biāo)coordinate,title,subtitle屬性;
  • 使用addAnnotation:添加大頭針數(shù)據(jù)源,在
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation

方法中添加大頭針視圖MKPinAnnotationView,并且設(shè)置拖動屬性為YES:pin.draggable = YES;

  • 下面方法是拖拽回調(diào)方法,在MKAnnotationViewDragStateEnding狀態(tài)時(shí),調(diào)整大頭針位置即可
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view didChangeDragState:(MKAnnotationViewDragState)newState
   fromOldState:(MKAnnotationViewDragState)oldState

最后的效果就是長按大頭針,會有一個(gè)大頭針升起的動畫,然后拖動釋放又會有大頭針落下的動畫,效果很炫。

這是使用系統(tǒng)方法實(shí)現(xiàn)大頭針的拖拽,其實(shí)也可以使用1中拖拽MKOverlayView的方法,在大頭針的位置放一個(gè)透明的子視圖,然后拖動這個(gè)子視圖的同時(shí),移除舊的大頭針,再在相應(yīng)位置添加新的大頭針即可。
只不過這就沒有大頭針升起/落下的動畫了,當(dāng)然,也不用長按大頭針才能拖動,你可以自定義。


3. 隨地圖的縮放而縮放的焦點(diǎn)框功能實(shí)現(xiàn)

由于系統(tǒng)沒有提供MKMapView的縮放比例,所以得自己計(jì)算這個(gè)比例:

  • 地圖縮放的時(shí)候其實(shí)是MKCoordinateSpan在變化
typedef struct {
    CLLocationDegrees latitudeDelta;//緯度范圍
    CLLocationDegrees longitudeDelta;//緯度范圍
} MKCoordinateSpan;
  • 比例計(jì)算公式
    float ratio = oldSpanArea/newSpan
    說明:老的span面積/新的span面積
    span面積=latitudeDelta * longitudeDelta

  • 最后計(jì)算焦點(diǎn)框的邊長
    float width = sqrtf(ratio * (fenceView.frame.size.width * fenceView.frame.size.height));
    然后改變焦點(diǎn)框的frame就可以了。
    當(dāng)然,最后的計(jì)算賦值都在縮放結(jié)束后的函數(shù)中進(jìn)行:

//當(dāng)拖拽,放大,縮小,雙擊手勢結(jié)束時(shí)調(diào)用
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated

補(bǔ)充:

前幾天對地圖這邊做優(yōu)化,發(fā)現(xiàn)方案三還可以有另一種做法:
可以通過給mapview對象添加:
UIPanGestureRecognizer,UITapGestureRecognizer,UIPinchGestureRecognizer
三種手勢來監(jiān)聽對地圖的拖動,點(diǎn)擊,縮放的事件,既然監(jiān)聽到了這些事件,那么后面的事情就好辦了。

當(dāng)然,不要忘了在代碼中實(shí)現(xiàn)UIGestureRecognizerDelegate的這個(gè)方法:

// called when the recognition of one of gestureRecognizer or otherGestureRecognizer would be blocked by the other
// return YES to allow both to recognize simultaneously. the default implementation returns NO (by default no two gestures can be recognized simultaneously)
//
// note: returning YES is guaranteed to allow simultaneous recognition. returning NO is not guaranteed to prevent simultaneous recognition, as the other gesture's delegate may return YES
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    return YES;
}

這個(gè)方法的意思是:
當(dāng)一個(gè)手勢被另外一個(gè)手勢堵塞后,就會調(diào)用這個(gè)回調(diào),默認(rèn)是返回NO的,
如果返回YES的話,才會允許多個(gè)手勢共存。

以上補(bǔ)充已在demo中添加。


Demo下載鏈接:CamouflageLocationDemo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容