前段時間辱挥,在項目上做了一些地圖相關(guān)的功能罩旋,解決了三個特殊需求,在此總結(jié)一下拯坟,以備日后使用:
1. MKOverlayView的拖動實現(xiàn)但金;
2. 大頭針pin 的拖動實現(xiàn);
3. 隨地圖的縮放而縮放的焦點框功能實現(xiàn)郁季;
1. MKOverlayView的拖動實現(xiàn)
首先冷溃,直接給MKOverlayView視圖本身添加一個拖動手勢是不可行的,因為MKOverlayView不是通過簡單的addSubview:
添加到地圖圖層上的梦裂。
MKOverlayView視圖的現(xiàn)實過程:
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 然后再實現(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;
}```
這樣就會給地圖的圖層中嵌入一個指定位置和大小的視圖年柠,效果上是與地圖合為一體的凿歼,可以一起移動和縮放,
也就是說通過`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的點坐標(biāo)攀唯,然后在同樣的位置加上一個同樣大小的透明子視圖,給自視圖添加拖動手勢UIPanGestureRecognizer
渴丸,每次拖動的時候先使用removeOverlay:
刪除之前的MKOverlayView侯嘀,然后再重新以拖動點為中心另凌,加載新的MKOverlayView即可,效果很良好戒幔,不會出現(xiàn)閃爍的現(xiàn)象吠谢。
由于地圖本身可以放大,縮小诗茎,移動工坊,所以在這些操作之后也需要調(diào)整這個子視圖的大小:
//當(dāng)拖拽敢订,放大王污,縮小,雙擊手勢開始時調(diào)用
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
//當(dāng)拖拽楚午,放大昭齐,縮小,雙擊手勢結(jié)束時調(diào)用
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
2. 大頭針pin 的拖動實現(xiàn)矾柜;
拖動大頭針的方法系統(tǒng)API有提供:
- 新建一個繼承
<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)時,調(diào)整大頭針位置即可
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view didChangeDragState:(MKAnnotationViewDragState)newState
fromOldState:(MKAnnotationViewDragState)oldState
最后的效果就是長按大頭針捆愁,會有一個大頭針升起的動畫割去,然后拖動釋放又會有大頭針落下的動畫,效果很炫昼丑。
這是使用系統(tǒng)方法實現(xiàn)大頭針的拖拽呻逆,其實也可以使用1中拖拽MKOverlayView的方法,在大頭針的位置放一個透明的子視圖菩帝,然后拖動這個子視圖的同時咖城,移除舊的大頭針,再在相應(yīng)位置添加新的大頭針即可呼奢。
只不過這就沒有大頭針升起/落下的動畫了宜雀,當(dāng)然,也不用長按大頭針才能拖動握础,你可以自定義辐董。
3. 隨地圖的縮放而縮放的焦點框功能實現(xiàn)
由于系統(tǒng)沒有提供MKMapView的縮放比例,所以得自己計算這個比例:
- 地圖縮放的時候其實是
MKCoordinateSpan
在變化
typedef struct {
CLLocationDegrees latitudeDelta;//緯度范圍
CLLocationDegrees longitudeDelta;//緯度范圍
} MKCoordinateSpan;
比例計算公式
float ratio = oldSpanArea/newSpan
說明:老的span面積/新的span面積
span面積=latitudeDelta * longitudeDelta最后計算焦點框的邊長
float width = sqrtf(ratio * (fenceView.frame.size.width * fenceView.frame.size.height));
然后改變焦點框的frame就可以了禀综。
當(dāng)然简烘,最后的計算賦值都在縮放結(jié)束后的函數(shù)中進行:
//當(dāng)拖拽苔严,放大,縮小孤澎,雙擊手勢結(jié)束時調(diào)用
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
補充:
前幾天對地圖這邊做優(yōu)化届氢,發(fā)現(xiàn)方案三還可以有另一種做法:
可以通過給mapview對象添加:
UIPanGestureRecognizer,UITapGestureRecognizer覆旭,UIPinchGestureRecognizer
三種手勢來監(jiān)聽對地圖的拖動退子,點擊,縮放的事件型将,既然監(jiān)聽到了這些事件絮供,那么后面的事情就好辦了。
當(dāng)然茶敏,不要忘了在代碼中實現(xiàn)UIGestureRecognizerDelegate
的這個方法:
// 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;
}
這個方法的意思是:
當(dāng)一個手勢被另外一個手勢堵塞后,就會調(diào)用這個回調(diào)缚俏,默認是返回NO的惊搏,
如果返回YES的話,才會允許多個手勢共存忧换。
以上補充已在demo中添加恬惯。
Demo下載鏈接:CamouflageLocationDemo