iOS上需要mapBox地图。(我不是在谈论MKMapView) 我们如何检测是否在mapView上点击了singleTap或注释?我需要只在地图的空白区域(没有引脚)处理singleTap,并且当我点击引脚时调用didSelectAnnotation。
但我在android上发现我们有这样的方法
mapboxMap.setOnMapClickListener(new MapboxMap.OnMapClickListener() {
public void onMapClick(@NonNull LatLng point) {
Toast.makeText(getActivity(),"on Tap "+point.getLatitude(),Toast.LENGTH_LONG).show();
}
});
以及
mapboxMap.setInfoWindowAdapter(new MapboxMap.InfoWindowAdapter() { ... })
将显示注释。
难道我们在iOS中没有相同的概念吗?
iOS中的实际问题是,当我在 Mapbox的mapView
上添加singleTapGesture
时
UITapGestureRecognizer *singleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
[self.mapView addGestureRecognizer:singleTapGesture];
mapbox的mapView 的委托方法不会调用。
- (nullable UIView <MGLCalloutView> *)mapView:(MGLMapView *)mapView calloutViewForAnnotation:(id <MGLAnnotation>)annotation;
要确保委托方法必须调用,那么我不必使用singleTapGesture
这里的情况要么是这个,要么就是这样,但根据我的需要,我需要两者。
期待任何解决方案。 谢谢,
答案 0 :(得分:2)
我在这里做了另一个解决方法
我克隆了 release-ios-v3.3.0 并使用Building the SDK创建了包,并添加了一个委托方法
MGLMapvViewDelegate.h
根据我的需要,这样的东西。
-(void)mapView:(MGLMapView *)mapView tapOnNonAnnotationAreaWithPoints:(CGPoint)points
在MGLMapView.mm中我更新了代码,
else{
if(self.selectedAnnotation)
[self deselectAnnotation:self.selectedAnnotation animated:YES];
else if([self.delegate respondsToSelector:@selector(mapView:tapOnNonAnnotationAreaWithPoints:)])
[self.delegate mapView:self tapOnNonAnnotationAreaWithPoints:tapPoint];
}
在-(void)handleSingleTapGesture:(UITapGestureRecognizer *)singleTap
方法中。
它为我工作,因为我能够检测到非注释区域的单击。之后我将传递的points
转换为地理坐标,以便我使用新的坐标坐标。
注意强>
答案 1 :(得分:1)
尝试swift 3
//determined is Point inner to realm polygons
func determinedInPoligon(point:CLLocationCoordinate2D, poligon:[CLLocationCoordinate2D]) -> Bool {
var result:Bool = false
var j = poligon.count - 1
for i in 0 ..< poligon.count {
if (poligon[i].longitude < point.longitude && poligon[j].longitude >= point.longitude || poligon[j].longitude < point.longitude && poligon[i].longitude >= point.longitude) &&
(poligon[i].latitude + (point.longitude - poligon[i].longitude) / (poligon[j].longitude - poligon[i].longitude) * (poligon[j].latitude - poligon[i].latitude) < point.latitude) {
result = !result;
}
j = i;
}
return result
}
func squareFrom(location: CGPoint, radius: Double) -> CGRect {//return rect with CGPoint center and radius
let length = radius
return CGRect(x: Double(location.x - CGFloat(length / 2)), y:
Double(location.y - CGFloat(length / 2)), width: length, height: length)
}
功能句柄
func handleTap(_ gesture: UITapGestureRecognizer) {
// Get the CGPoint where the user tapped.
let spot = gesture.location(in: mapView)
let my_features = mapView.visibleFeatures(at: spot)
let strZoomValue = mapView.zoomLevel > 15 ? "6" : "4"
//the feature structur object value not equal annotation object
for value in my_features.enumerated() {// feature items
if value.element is MGLPointAnnotation {
for annot in (mapView.annotations?.enumerated())! { // annotation items
if annot.element is MGLPointAnnotation {
//rounded lat and lng value
var arr_cllocation = [CLLocationCoordinate2D]()
for cllocation in [(annot.element as! MGLPointAnnotation).coordinate, (value.element as! MGLPointAnnotation).coordinate] {
let strLat = String(format: "%."+strZoomValue+"f", cllocation.latitude)
let strLon = String(format: "%."+strZoomValue+"f", cllocation.longitude)
arr_cllocation.append(
CLLocationCoordinate2D(latitude: CLLocationDegrees(strLat)!, longitude: CLLocationDegrees(strLon)!) )
}
if arr_cllocation.count == 2 &&
memcmp(&arr_cllocation[0], &arr_cllocation[1], MemoryLayout<CLLocationCoordinate2D>.size) == 0 {// 0 if equal object
// to do custom popup view
let instViewPopupLineClass = UINib(nibName: "ViewPopupBase", bundle: nil).instantiate(withOwner: self, options: nil).first as! UIView
for objectInst in instViewPopupLineClass.subviews.enumerated() {
if objectInst.element is UILabel {
let asdasdas = (annot.element as! MGLPointAnnotation).subtitle
(objectInst.element as! UILabel).text = asdasdas
MyCustomPopup(customView: instViewPopupLineClass, positionXY: spot)
break
}
}
}
}
} //for end
}
}
}
或不准确的方法,但是工人;)
func handleTap(_ gesture: UITapGestureRecognizer) {// Get the CGPoint where the user tapped.
let spot = gesture.location(in: mapView)
let cllcordinatTap = mapView.convert(spot, toCoordinateFrom: mapView)
//for determined zoom scala
let deltScalaMap = abs(self.mapView.maximumZoomLevel - self.mapView.zoomLevel)
//The large is zoom maps, then smal size is tap location, and vice versa.
let checkScalaMap = deltScalaMap == 0 ? 1 : deltScalaMap
let _rect = squareFrom(location: CGPoint(x: cllcordinatTap.latitude, y: cllcordinatTap.longitude), radius: 0.00005 * checkScalaMap)
for annot in (mapView.annotations?.enumerated())! {
if annot.element is MGLPointAnnotation {
let _cordinatCurrentAnnotation = (annot.element as! MGLPointAnnotation).coordinate
if determinedInPoligon(point: _cordinatCurrentAnnotation, poligon:
[CLLocationCoordinate2D(latitude: CLLocationDegrees(_rect.minX), longitude: CLLocationDegrees(_rect.minY)),
CLLocationCoordinate2D(latitude: CLLocationDegrees(_rect.maxX), longitude: CLLocationDegrees(_rect.minY)),
CLLocationCoordinate2D(latitude: CLLocationDegrees(_rect.maxX), longitude: CLLocationDegrees(_rect.maxY)),
CLLocationCoordinate2D(latitude: CLLocationDegrees(_rect.minX), longitude: CLLocationDegrees(_rect.maxY))
]) {
// to do, if tap MGLPointAnnotation, annot.element
}
}
}
}
答案 2 :(得分:1)
子类MGLMapView并委托其“INDEX
。
touchesEnded
当调用protocol MapViewTapDelegate: class {
func mapViewTapped(withTouchLocation touchLocation: CLLocationCoordinate2D)
}
class MapView: MGLMapView {
weak var tapDelegate: MapViewTapDelegate?
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
guard let touch = touches.first else { return }
let touchLocation = convert(touch.location(in: self), toCoordinateFrom: nil)
tapDelegate?.mapViewTapped(withTouchLocation: touchLocation)
}
}
时未触发touchesEnded
,反之亦然,这就是您所需要的。
didSelect annotation
答案 3 :(得分:0)
-(void)mapView:(MGLMapView *)mapView didSelectAnnotation:(id<MGLAnnotation>)annotation
将解决您选择注释的问题。
答案 4 :(得分:0)
我为您的问题尝试了示例项目,效果很好。
·H
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
@interface ViewController : UIViewController<MKMapViewDelegate>
@property (strong, nonatomic) IBOutlet MKMapView *mapTapAnnotation;
@end
的.m
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
@synthesize mapTapAnnotation;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self setMapViewWithAnnnoationPin];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)setMapViewWithAnnnoationPin
{
mapTapAnnotation.showsUserLocation = YES;
mapTapAnnotation.mapType = MKMapTypeHybrid;
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(12.900988, 80.227930);
MKCoordinateSpan span = MKCoordinateSpanMake(0.005, 0.005);
MKCoordinateRegion region = {coord, span};
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
[annotation setCoordinate:coord];
[annotation setTitle:@"Single Tap"]; //You can set the subtitle too
[mapTapAnnotation setRegion:region];
[mapTapAnnotation addAnnotation:annotation];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(detectSingleTap)];
tapGesture.numberOfTapsRequired = 1;
[mapTapAnnotation addGestureRecognizer:tapGesture];
}
-(void)detectSingleTap
{
NSLog(@"Finded the single tap on map view");
}
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
NSLog(@"The single tap annotation pin point is - %ld",(long)view.tag);
}
打印输出结果为
Finded the single tap on map view
The single tap annotation pin point is - 0
答案 5 :(得分:0)
在这里,我得到了一些有助于满足我的要求的解决方法。 根据我的需要,我可以在 mapbox注释标记以及地图的空白区域
上进行单击检测我为MGLMapView创建了类别,( MGLMapView + EDCMapboxView )并覆盖了触摸方法
-touchesBegan:withEvent:
-touchesMoved:withEvent:
-touchesEnded:withEvent:
-touchesCancelled:withEvent:
<强> MGLMapView + EDCMapboxView.h 强>
@protocol EDCMapboxViewDelegate <NSObject>
@optional
- (void)mapboxViewDidCreateNewTicket:(MGLMapView*)mapView;
@end
@interface MGLMapView (EDCMapboxView)
@property (assign, nonatomic) BOOL shouldCreateNewTicket;
@property (weak, nonatomic) id <EDCMapboxViewDelegate> mapboxDelegate;
@end
<强> MGLMapView + EDCMapboxView.m 强>
@implementation MGLMapView (EDCMapboxView)
@dynamic mapboxDelegate;
#pragma mark -- Accessor
- (BOOL)shouldCreateNewTicket {
return [objc_getAssociatedObject(self, @selector(shouldCreateNewTicket)) boolValue];
}
- (void)setShouldCreateNewTicket:(BOOL)flag {
objc_setAssociatedObject(self, @selector(shouldCreateNewTicket), @(flag), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(id<EDCMapboxViewDelegate>)mapboxDelegate{
return objc_getAssociatedObject(self, @selector(mapboxDelegate));
}
- (void)setMapboxDelegate:(id<EDCMapboxViewDelegate>)mapboxDelegate{
objc_setAssociatedObject(self, @selector(mapboxDelegate), mapboxDelegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#pragma mark -- Overrided method for UIResponder
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event{
NSLog(@"touchesBegan");
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event{
NSLog(@"touchesMoved");
self.shouldCreateNewTicket = NO;
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event{
NSLog(@"touchesEnded");
}
- (void)touchesCancelled:(nullable NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event{
NSLog(@"touchesCancelled");
[self createNewTicket];
}
- (void)createNewTicket{
if(self.shouldCreateNewTicket){
NSLog(@"Allowed to Create New ticket");
// Tells that tap is on empty area.
if([self.mapboxDelegate respondsToSelector:@selector(mapboxViewDidCreateNewTicket:)]){
[self.mapboxDelegate mapboxViewDidCreateNewTicket:self];
}
}
else{
NSLog(@"Not allowed to create New ticket");
// Tells tap is on annotation marker.
self.shouldCreateNewTicket = YES;
}
}
<强> EDCMapboxViewController.m 强>
- (void)viewDidLoad {
[super viewDidLoad];
self.mapView.shouldCreateNewTicket = YES;
.....
.......
........
}
- (BOOL)mapView:(MGLMapView *)mapView annotationCanShowCallout:(id <MGLAnnotation>)annotation {
NSLog(@"annotationCanShowCallout");
// Tells that annotation is tapped, then do not allow to create ticket.
self.mapView.shouldCreateNewTicket = NO;
return YES;
}
- (void)mapboxViewDidCreateNewTicket:(MGLMapView*)mapView{
// Tells that tap is on empty area and not on marker, then allow to create ticket.
}
它对我有用,希望它也会帮助你们。 感谢。
答案 6 :(得分:0)
以下是我如何解决它,你应该得到这个概念。
func onMapSingleTapped(recognizer: UITapGestureRecognizer)
{
let viewLocation: CGPoint = recognizer.locationInView(map)
// check if any annotations are hit
if(map.annotations != nil)
{
for annotation in map.annotations!
{
if(annotation.isKindOfClass(MapCheckInAnnotation))
{
let pin: MapCheckInAnnotation = annotation as! MapCheckInAnnotation
if let pinView = pin.view
{
print("pinview \(pinView.frame.origin)")
// check if hit pin instead of just map
if(viewLocation.x >= pinView.frame.origin.x && viewLocation.x < pinView.frame.origin.x + pinView.frame.width)
{
if(viewLocation.y >= pinView.frame.origin.y && viewLocation.y < pinView.frame.origin.y + pinView.frame.height)
{
mapView(map, didSelectAnnotationView: pinView)
return
}
}
}
}
}
}
// nope, no annotations were clicked
let mapLocation: CLLocationCoordinate2D = map.convertPoint(viewLocation, toCoordinateFromView: map)
print("onMapSingleTapped \(mapLocation)")
}
答案 7 :(得分:0)
由于我在上述解决方案上没有取得成功,因此在始终认可的地图点击事件之后实施了一个小的延迟。如果在此较小的时间范围内选择了注释,则不会再调用任何东西。否则,仅点击地图视图,不添加注释。 就我而言,效果很好。
MapView零件
protocol MapDelegate: class {
func didTapMapView()
}
class AppleMapView: MKMapView {
weak var mapDelegate: MapDelegate?
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
if touches.first != nil {
mapDelegate?.didTapMapView()
}
}
........
}
MapViewController部分
// property to store last tap at annotation
var lastAnnotationSelectionTime = Date()
// this method is called on every tap
func didTapMapView() {
let overlaySelectionDelayTime: TimeInterval = 0.2
DispatchQueue.main.asyncAfter(deadline: .now() + overlaySelectionDelayTime, execute: { [weak self] in
guard let self = self else { return }
if self.lastAnnotationSelectionTime.distance(to: Date()) > overlaySelectionDelayTime {
// only called if no annotation was tapped meanwhile
[ HANDLE TAP ON MAP HERE ]
}
})
}
// MARK: Marker Selection
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
lastAnnotationSelectionTime = Date() // setten if annotation is tapped
[ HANDLE TAP ON ANNOTATION HERE ]
}