使用苹果自带地图获取当前位置及周围信息

天朝的网络在XXX的干预下,我们很多内容都不能正常访问,需要翻墙。处在这样一个大的局域网环境之下,作为IT行业的我们很是苦恼,如果做的应用要世界通用,那就是痛苦了,需要考虑很多。例如:如果我们做一个地图应用,兼容中国和外国。要么使用国内地图+Google,要么就是使用苹果自带地图。今天主要介绍使用苹果自带地图获取用户当前位置及用户周围信息,地图移动时,地图中间大头针一直在中间,移动结束后有下落定位的动画效果并更新当前位置及用户周围信息。需要真机测试查看效果。

先看效果:
gif动画是在模拟器上录制,由于模拟器不能获取周围信息,所以一直在转菊花。要看实际效果需要真机查看。

IMG_2365.PNG

步骤

  1. 添加库MapKit.framework

    模拟器效果展示

  2. 打开地图功能。


    真机截图
  3. 代码实现。

  • 在用户位置显示完成后添加一个固定的ImageView在地图正中间。
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
    NSLog(@"userLocation:longitude:%f---latitude:%f",userLocation.location.coordinate.longitude,userLocation.location.coordinate.latitude);
    if (!haveGetUserLocation) {
        if (self.mapView.userLocationVisible) {
            haveGetUserLocation = YES;
            [self getAddressByLatitude:userLocation.coordinate.latitude longitude:userLocation.coordinate.longitude];
            [self addCenterLocationViewWithCenterPoint:self.mapView.center];
        }
        
    }
}


-(void)addCenterLocationViewWithCenterPoint:(CGPoint)point
{
    if (!imgView) {
        imgView = [[UIImageView alloc]initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2, 100, 18, 38)];
        imgView.center = point;
        imgView.image = [UIImage imageNamed:@"map_location"];
        imgView.center = self.mapView.center;
        [self.view addSubview:imgView];
    }
    
}

  • 获取当前位置周围信息,苹果提供了一个请求方法,MKLocalSearch。其官方介绍为:

An MKLocalSearch object initiates a map-based search operation and delivers the results back to your app asynchronously. Search objects are designed to perform one search operation only. To perform several different searches, you must create separate instances of this class and start them separately.
也就是说我们如果要搜索不同的类型需要分别创建多个实例进行操作。

如果我们要搜索周围100米餐厅代码如下:

    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(coordinate,100, 100);
    MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc]init];
    request.region = region;
    request.naturalLanguageQuery = @"Restaurants";
    MKLocalSearch *localSearch = [[MKLocalSearch alloc]initWithRequest:request];
    [localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error){
        if (!error) {
            //do something.
        }else{
            //do something.
        }
    }];

其中naturalLanguageQuery就是要搜索的关键字,我试过的所有关键字有cafe, supermarket,village,Community,Shop,Restaurant,School,hospital,Company,Street,Convenience store,Shopping Centre,Place names,Hotel,Grocery store每个关键字搜索返回结果只有10条,如果当前范围无搜索结果,则扩散搜索范围。如果你想列出周围所有相关位置信息,我认为需要尽可能的把所有的能够想到的关键字都举例出来进行搜索,搜索完成后进行经纬度比较然后刷选出范围内的相关位置。而且由于数据来源问题,很多位置信息都没有!当然如果你只兼容国内,还是使用百度或者腾讯地图算了。

  • 根据经纬度获取位置相关信息。
    CLLocation *location=[[CLLocation alloc]initWithLatitude:latitude longitude:longitude];
    [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
        if (!error) {
            dispatch_async(dispatch_get_main_queue(), ^{
            //do something.
            });
        }else{
            //do something.
        }
        
    }];
  • 下落定位动画效果
     imgView.center = CGPointMake(mapCenter.x, mapCenter.y-15);
     [UIView animateWithDuration:0.2 animations:^{
            imgView.center = mapCenter;
        }completion:^(BOOL finished){
            if (finished) {
                [UIView animateWithDuration:0.05 animations:^{
                    imgView.transform = CGAffineTransformMakeScale(1.0, 0.8);
                    
                }completion:^(BOOL finished){
                    if (finished) {
                        [UIView animateWithDuration:0.1 animations:^{
                            imgView.transform = CGAffineTransformIdentity;
                        }];
                    }
                }];
            }
      }];

这里我的思路是三个动画效果组合以达到大头针下落定位的效果。

  • 获取用户滑动地图操作。
    MKMapViewDelegate中有个方法在滑动结束后可以回调如下所示:
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated

因为回调是在展示的地图区域改变后调用,所以使用它有个缺点就是在最开始初始化地图并定位到用户所在位置时,它会被反复回调。所以很难确定用户是否是滑动。所以这里我们需要知道用户是否和地图有过滑动后导致它的回调。如何做呢?这里有两种方法以供参考。
方法一:这里你是否想起UIScrollView,如果我们想获取touch事件,我们应该怎么做,没错就是继承后重写touch方法,然后把toush事件传递下去。代码如下:

@implementation ZHMapView

#pragma mark - touchs
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];
    [[self nextResponder] touchesBegan:touches withEvent:event];
}

-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [super touchesMoved:touches withEvent:event];
    [[self nextResponder] touchesMoved:touches withEvent:event];
}

-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [super touchesEnded:touches withEvent:event];
    [[self nextResponder] touchesEnded:touches withEvent:event];
  
}

- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event
{
     [super touchesCancelled:touches withEvent:event];
    [[self nextResponder]touchesCancelled:touches withEvent:event];
}

方法二:我在修改 navigationBar 底部线条颜色总结这篇文章中有用到查看View层次结构找到隐藏属性并对它进行操作。没错这里也是一样的道理,先看mapview层次结构例如如下所示:


这里我们可以发现_MKMapContentView里面有个手势数组,没错就是它了。我们获取它并对他进行操作,代码如下所示:

//打印完后我们发现有个View带有手势数组其类型为_MKMapContentView获取Span手势
    for (UIView *view in self.mapView.subviews) {
        NSString *viewName = NSStringFromClass([view class]);
        if ([viewName isEqualToString:@"_MKMapContentView"]) {
            UIView *contentView = view;//[self.mapView valueForKey:@"_contentView"];
            for (UIGestureRecognizer *gestureRecognizer in contentView.gestureRecognizers) {
                if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
                    [gestureRecognizer addTarget:self action:@selector(mapViewSpanGesture:)];
                }
            }

        }
    }

  • 加载时UITableView顶部展示菊花展示,这个原理和我们做分页展示时,滑动到底部或顶部有个菊花展示的道理一样。代码如下
#pragma mark - Private Methods
-(void)resetTableHeadView
{
    if (infoArray.count>0) {
        self.showTableView.tableHeaderView = nil;
    }else{
        UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 30.0)];
        view.backgroundColor = self.showTableView.backgroundColor;
        UIActivityIndicatorView *indicatorView = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
        indicatorView.center = view.center;
        [indicatorView startAnimating];
        [view addSubview:indicatorView];
        self.showTableView.tableHeaderView = view;
        
    }
}

下载地址

GitHub

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 175,090评论 25 709
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 14,194评论 4 61
  • 那天我和老友们接他放假,他在我们那所城市最好的高中就读,说实话在和他商量好要接他之前的几个小时里我心里特别激...
    夏嗯阅读 1,729评论 0 1
  • 一 宇宙一何衰,兴亡皆稊米。 草木知吾醉,深深封石肆。 二 故园植新韭,采采与人依。 向无春日暖,安得清嫩毗。 复...
    专治各种嘚瑟阅读 2,463评论 1 2
  • 你们曾经吃过最棒的秘制鸡腿饭究竟有多好吃呢?照烧的口感,鲜嫩的鸡肉,松脆的表皮,烤的金黄的鸡肉上刷着一层浓稠的焦糖...
    味库美食视频阅读 2,839评论 1 4