美文网首页
iOS 百度地图方便Mac下打开

iOS 百度地图方便Mac下打开

作者: 红太羊_8225 | 来源:发表于2021-03-15 12:32 被阅读0次

    本篇文章记录了:

    引入百度地图API

    如何显示地图并定位

    如何定位获取经纬度

    如何通过定位得到城市,国家,街道等信息

    如何通过搜索地理名获得坐标

    如何实现公交和驾车路线搜索

    如何实现当前位置到指定位置的公交和驾车路线搜索

    引入百度地图API

    首先,需要到http://dev.baidu.com/wiki/imap/index.php?title=iOS平台/相关下载下载全部内容,包括文档,示例代码和开发包。

    然后获取自己的API KEY,具体方法按百度的官网申请就行,比较简单。

    下载的文件应该有三个

    把inc文件夹拖入到项目中去,引入了头文件,然后如果用真机就把Release-iphoneos里面的.a文件拖拽到项目中去,最后别忘了拖入mapapi.bundle文件,路线节点和图钉的图片来源于素材包。

    此外还要引入CoreLocation.framework和QuartzCore.framework,这样引入工作就大功告成,但是要注意一点 很重要的,静态库中采用ObjectC++实现,因此需要保证工程中至少有一个.mm后缀的源文件(您可以将任意一个.m后缀的文件改名为.mm),或者 在工程属性中指定编译方式,即将XCode的Project -> Edit Active Target -> Build -> GCC4.2 – Language -> Compile Sources As设置为”Objective-C++”。

    经过实践,我推荐不这么干,默认是根据文件类型来选择编译的方式,文件要是.m就用Objective-C,要是.mm就是Objective- C++,手动改变会让整个项目都用一种编译方式,很容易出错或者不兼容,比如NavigationItem实例化的时候就会出错,既然百度地图如此特立独 行,那么最好的方式就是把地图相关的类改为.mm,其他的依旧,这样只有这个类会用Objective-C++编译方式。

    如何显示地图并定位

    要让车发动起来先得有引擎,所以在项目的根delegate类里就要通过BMKMapManager这个类来实现地图引擎的启动,具体代码:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

    {

    //要使用百度地图,请先启动BaiduMapManager

    _mapManager = [[BMKMapManager alloc]init];

    //如果要关注网络及授权验证事件,请设定generalDelegate参数

    BOOL ret = [_mapManager start:@"C5DCEBF3F591FCB69EE0A0B9B1BB4C948C3FA3CC" generalDelegate:nil];

    if (!ret) {

    NSLog(@”manager start failed!”);

    }

    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];

    // Override point for customization after application launch.

    self.viewController = [[[ViewController alloc] initWithNibName:@”ViewController” bundle:nil] autorelease];

    self.window.rootViewController = self.viewController;

    [self.window makeKeyAndVisible];

    return YES;

    }

    接下来要做的就是添加地图视图,在需要地图的类头文件里添加如下代码(这个类应该是.mm文件):

    #import <UIKit/UIKit.h>

    #import “BMapKit.h”

    @interface testViewController : UIViewController//两个协议要引入

    {

    BMKSearch* _search;//搜索要用到的

    BMKMapView* mapView;//地图视图

    IBOutlet UITextField* fromeText;

    NSString  *cityStr;

    NSString *cityName;

    CLLocationCoordinate2D startPt;

    float localLatitude;

    float localLongitude;

    BOOL localJudge;

    NSMutableArray *pathArray;

    }

    @end

    一些成员后面要用到先不提,这里只是实现地图的显示和定位,然后在.mm文件里,在@implementation testViewController的前面添加这些代码

    #import “testViewController.h”

    #define MYBUNDLE_NAME @ “mapapi.bundle”

    #define MYBUNDLE_PATH [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent: MYBUNDLE_NAME]

    #define MYBUNDLE [NSBundle bundleWithPath: MYBUNDLE_PATH]

    BOOL isRetina = FALSE;

    @interface RouteAnnotation : BMKPointAnnotation

    {

    int _type; ///<0:起点 1:终点 2:公交 3:地铁 4:驾乘

    int _degree;

    }

    @property (nonatomic) int type;

    @property (nonatomic) int degree;

    @end

    @implementation RouteAnnotation

    @synthesize type = _type;

    @synthesize degree = _degree;

    @end

    @interface UIImage(InternalMethod)

    - (UIImage*)imageRotatedByDegrees:(CGFloat)degrees;

    @end

    @implementation UIImage(InternalMethod)

    - (UIImage*)imageRotatedByDegrees:(CGFloat)degrees

    {

    CGSize rotatedSize = self.size;

    if (isRetina) {

    rotatedSize.width *= 2;

    rotatedSize.height *= 2;

    }

    UIGraphicsBeginImageContext(rotatedSize);

    CGContextRef bitmap = UIGraphicsGetCurrentContext();

    CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);

    CGContextRotateCTM(bitmap, degrees * M_PI / 180);

    CGContextRotateCTM(bitmap, M_PI);

    CGContextScaleCTM(bitmap, -1.0, 1.0);

    CGContextDrawImage(bitmap, CGRectMake(-rotatedSize.width/2, -rotatedSize.height/2, rotatedSize.width, rotatedSize.height), self.CGImage);

    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return newImage;

    }

    @end

    有些代码对实现定位没有帮助,但是后面要用到,并且demo示例代码也是这么写的,所以引入了没有坏处,之后给这个类添加一个方法,获取图片资源用:

    - (NSString*)getMyBundlePath1:(NSString *)filename

    {

    NSBundle * libBundle = MYBUNDLE ;

    if ( libBundle && filename ){

    NSString * s=[[libBundle resourcePath ] stringByAppendingPathComponent : filename];

    NSLog ( @”%@” ,s);

    return s;

    }

    return nil ;

    }

    下面才是真正添加地图的地方:

    - (void)viewDidLoad

    {

    [super viewDidLoad];

    mapView = [[BMKMapView alloc]initWithFrame:CGRectMake(0, 92, 320, 388)];

    [self.view addSubview:mapView];

    mapView.delegate = self;

    [mapView setShowsUserLocation:YES];//显示定位的蓝点儿

    _search = [[BMKSearch alloc]init];//search类,搜索的时候会用到

    _search.delegate = self;

    fromeText.text=@”新中关”;

    CGSize screenSize = [[UIScreen mainScreen] currentMode].size;

    if ((fabs(screenSize.width – 640.0f) < 0.1)

    && (fabs(screenSize.height – 960.0f) < 0.1))

    {

    isRetina = TRUE;

    }

    pathArray=[[NSMutableArray array] retain];  //用来记录路线信息的,以后会用到

    }

    然后我在ib拖拽了几个按钮,功能显而易见,编译运行就应该成功了

    如何定位获取经纬度和如何通过定位得到城市,国家,街道等信息

    这两个问题一段代码就可以解决,所以归并在一起,当添加了地图引擎和设定setShowsUserLocation:YES以后,地图已经在定位了,通过代理方法可以获得经纬度信息,并通过经纬度信息我可以获得街道城市等信息:

    //百度定位获取经纬度信息

    -(void)mapView:(BMKMapView *)mapView didUpdateUserLocation:(BMKUserLocation *)userLocation{

    NSLog(@”!latitude!!!  %f”,userLocation.location.coordinate.latitude);//获取经度

    NSLog(@”!longtitude!!!  %f”,userLocation.location.coordinate.longitude);//获取纬度

    localLatitude=userLocation.location.coordinate.latitude;//把获取的地理信息记录下来

    localLongitude=userLocation.location.coordinate.longitude;

    CLGeocoder *Geocoder=[[CLGeocoder alloc]init];//CLGeocoder用法参加之前博客

    CLGeocodeCompletionHandler handler = ^(NSArray *place, NSError *error) {

    for (CLPlacemark *placemark in place) {

    cityStr=placemark.thoroughfare;

    cityName=placemark.locality;

    NSLog(@”city %@”,cityStr);//获取街道地址

    NSLog(@”cityName %@”,cityName);//获取城市名

    break;

    }

    };

    CLLocation *loc = [[CLLocation alloc] initWithLatitude:userLocation.location.coordinate.latitude longitude:userLocation.location.coordinate.longitude];

    [Geocoder reverseGeocodeLocation:loc completionHandler:handler];

    }

    其实,街道地址是不准确的,因为精度和纬度是不正确的,地址来源于经纬度,至于为什么不正确应该是因为”火星坐标系”,这里不做深入研究。

    如何通过搜索地理名获得坐标

    这个例子里是通过点击公交按钮,获得textfield里面内容地点到三里屯的公交路线信息,起点是textfield里面的内容,终点固定是三里屯。

    事实上,获取路线需要得到起点的坐标,所以通过地理名获得坐标是后面获取路线的第一步。

    在搜索的时候调用:

    BOOL flag = [_search geocode:fromeText.text withCity:cityStr];//这里用到之前定义的search了

    if (!flag) {

    NSLog(@”search failed”);

    }

    geocode第一个参数是fromeText,默认我写的是新中关,withCity是定位获得的城市,调用这个方法以后,结果会传给代理方法:

    - (void)onGetAddrResult:(BMKAddrInfo*)result errorCode:(int)error{

    NSLog(@”11111   %f”,result.geoPt.latitude);//获得地理名“新中关”的纬度

    NSLog(@”22222   %f”,result.geoPt.longitude);//获得地理名“心中关”的经度

    NSLog(@”33333 %@”,result.strAddr);//街道名

    NSLog(@”4444 %@”,result.addressComponent.province);//所在省份

    NSLog(@”555 %@”,result.addressComponent.city);

    startPt = (CLLocationCoordinate2D){0, 0};

    startPt = result.geoPt;//把坐标传给startPt保存起来

    }

    这里可以看到好像百度地图api的结果都不是直接获得的,而是传给对应的代理方法。接下来的路线获取也一样

    如何实现公交和驾车路线搜索

    当textfield里面默认是新中关的时候,我的驾乘按钮代码如下:

    -(IBAction)onClickDriveSearch

    {

    //清除之前的路线和标记

    NSArray* array = [NSArray arrayWithArray:mapView.annotations];

    [mapView removeAnnotations:array];

    array = [NSArray arrayWithArray:mapView.overlays];

    [mapView removeOverlays:array];

    //清楚路线方案的提示信息

    [pathArray removeAllObjects];

    //如果是从当前位置为起始点

    if (localJudge) {

    BMKPlanNode* start = [[BMKPlanNode alloc]init];

    startPt.latitude=localLatitude;

    startPt.longitude=localLongitude;

    start.pt = startPt;

    start.name = cityStr;

    BMKPlanNode* end = [[BMKPlanNode alloc]init];

    end.name = @”三里屯”;

    BOOL flag1 = [_search drivingSearch:cityName startNode:start endCity:@"北京市" endNode:end];

    if (!flag1) {

    NSLog(@”search failed”);

    }

    [start release];

    [end release];

    }else {

    //如果从textfield获取起始点,不定位的话主要看这里

    BOOL flag = [_search geocode:fromeText.text withCity:cityStr];//通过搜索textfield地名获得地名的经纬度,之前已经讲过了,并存储在变量startPt里

    if (!flag) {

    NSLog(@”search failed”);

    }

    BMKPlanNode* start = [[BMKPlanNode alloc]init];

    start.pt = startPt;//起始点坐标

    start.name = fromeText.text;//起始点名字

    BMKPlanNode* end = [[BMKPlanNode alloc]init];

    end.name = @”三里屯”;//结束点名字

    BOOL flag1 = [_search drivingSearch:cityName startNode:start endCity:@"北京市" endNode:end];//这个就是驾车路线查询函数,利用了startPt存储的起始点坐标,会调用代理方法 onGetDrivingRouteResult

    if (!flag1) {

    NSLog(@”search failed”);

    }

    [start release];

    [end release];

    }

    }

    大致就是这样的逻辑,通过geocode函数得到地名坐标,然后通过drivingSearch函数设定起始点和结束点,并调用代理方法来利用这个路线结果,下面就是代理方法

    //驾车的代理方法

    - (void)onGetDrivingRouteResult:(BMKPlanResult*)result errorCode:(int)error

    {

    NSLog(@”onGetDrivingRouteResult:error:%d”, error);

    if (error == BMKErrorOk) {

    BMKRoutePlan* plan = (BMKRoutePlan*)[result.plans objectAtIndex:0];

    RouteAnnotation* item = [[RouteAnnotation alloc]init];

    item.coordinate = result.startNode.pt;

    item.title = @”起点”;

    item.type = 0;

    [mapView addAnnotation:item];

    [item release];

    int index = 0;

    int size = [plan.routes count];

    for (int i = 0; i < 1; i++) {

    BMKRoute* route = [plan.routes objectAtIndex:i];

    for (int j = 0; j < route.pointsCount; j++) {

    int len = [route getPointsNum:j];

    index += len;

    }

    }

    BMKMapPoint* points = new BMKMapPoint[index];

    index = 0;

    for (int i = 0; i < 1; i++) {

    BMKRoute* route = [plan.routes objectAtIndex:i];

    for (int j = 0; j < route.pointsCount; j++) {

    int len = [route getPointsNum:j];

    BMKMapPoint* pointArray = (BMKMapPoint*)[route getPoints:j];

    memcpy(points + index, pointArray, len * sizeof(BMKMapPoint));

    index += len;

    }

    size = route.steps.count;

    for (int j = 0; j < size; j++) {

    BMKStep* step = [route.steps objectAtIndex:j];

    item = [[RouteAnnotation alloc]init];

    item.coordinate = step.pt;

    item.title = step.content;

    item.degree = step.degree * 30;

    item.type = 4;

    [mapView addAnnotation:item];

    [item release];

    //把每一个步骤的提示信息存储到pathArray里,以后可以用这个内容实现文字导航

    [pathArray addObject:step.content];

    }

    }

    item = [[RouteAnnotation alloc]init];

    item.coordinate = result.endNode.pt;

    item.type = 1;

    item.title = @”终点”;

    [mapView addAnnotation:item];

    [item release];

    BMKPolyline* polyLine = [BMKPolyline polylineWithPoints:points count:index];

    [mapView addOverlay:polyLine];

    delete []points;

    //打印pathArray,检验获取的文字导航提示信息

    for (NSString *string in pathArray) {

    NSLog(@”patharray2 %@”,string);

    }

    }

    }

    这样驾车的路线就应该可以获取了,编译运行可以看到路线图,同时可以从打印的数组信息得到提示信息,内容就是地图上点击节点弹出的内容

    同理,公交按钮的代码:

    -(IBAction)onClickBusSearch

    {

    //清空路线

    NSArray* array = [NSArray arrayWithArray:mapView.annotations];

    [mapView removeAnnotations:array];

    array = [NSArray arrayWithArray:mapView.overlays];

    [mapView removeOverlays:array];

    [pathArray removeAllObjects];

    if (localJudge) {

    //开始搜索路线,transitSearch调用onGetTransitRouteResult

    BMKPlanNode* start = [[BMKPlanNode alloc]init];

    startPt.latitude=localLatitude;

    startPt.longitude=localLongitude;

    start.pt = startPt;

    start.name = cityStr;

    BMKPlanNode* end = [[BMKPlanNode alloc]init];

    end.name = @”三里屯”;

    BOOL flag1 = [_search transitSearch:cityName startNode:start endNode:end];

    if (!flag1) {

    NSLog(@”search failed”);

    }

    [start release];

    [end release];

    }else{

    //由textfield内容搜索,调用onGetAddrResult函数,得到目标点坐标startPt

    BOOL flag = [_search geocode:fromeText.text withCity:cityStr];

    if (!flag) {

    NSLog(@”search failed”);

    }

    //开始搜索路线,transitSearch调用onGetTransitRouteResult

    BMKPlanNode* start = [[BMKPlanNode alloc]init];

    start.pt = startPt;

    start.name = fromeText.text;

    BMKPlanNode* end = [[BMKPlanNode alloc]init];

    end.name = @”三里屯”;

    BOOL flag1 = [_search transitSearch:cityName startNode:start endNode:end];//公交路线对应的代理方法是onGetTransitRouteResult

    if (!flag1) {

    NSLog(@”search failed”);

    }

    [start release];

    [end release];

    }

    }

    公交路线代理方法,这里和驾车路线不同的是,获取的提示信息不在一起,分上车信息和下车信息:

    - (void)onGetTransitRouteResult:(BMKPlanResult*)result errorCode:(int)error

    {

    NSLog(@”onGetTransitRouteResult:error:%d”, error);

    if (error == BMKErrorOk) {

    BMKTransitRoutePlan* plan = (BMKTransitRoutePlan*)[result.plans objectAtIndex:0];

    RouteAnnotation* item = [[RouteAnnotation alloc]init];

    item.coordinate = plan.startPt;

    item.title = @”起点”;

    item.type = 0;

    [mapView addAnnotation:item];

    [item release];

    item = [[RouteAnnotation alloc]init];

    item.coordinate = plan.endPt;

    item.type = 1;

    item.title = @”终点”;

    [mapView addAnnotation:item];

    [item release];

    int size = [plan.lines count];

    int index = 0;

    for (int i = 0; i < size; i++) {

    BMKRoute* route = [plan.routes objectAtIndex:i];

    for (int j = 0; j < route.pointsCount; j++) {

    int len = [route getPointsNum:j];

    index += len;

    }

    BMKLine* line = [plan.lines objectAtIndex:i];

    index += line.pointsCount;

    if (i == size – 1) {

    i++;

    route = [plan.routes objectAtIndex:i];

    for (int j = 0; j < route.pointsCount; j++) {

    int len = [route getPointsNum:j];

    index += len;

    }

    break;

    }

    }

    BMKMapPoint* points = new BMKMapPoint[index];

    index = 0;

    for (int i = 0; i < size; i++) {

    BMKRoute* route = [plan.routes objectAtIndex:i];

    for (int j = 0; j < route.pointsCount; j++) {

    int len = [route getPointsNum:j];

    BMKMapPoint* pointArray = (BMKMapPoint*)[route getPoints:j];

    memcpy(points + index, pointArray, len * sizeof(BMKMapPoint));

    index += len;

    }

    BMKLine* line = [plan.lines objectAtIndex:i];

    memcpy(points + index, line.points, line.pointsCount * sizeof(BMKMapPoint));

    index += line.pointsCount;

    item = [[RouteAnnotation alloc]init];

    item.coordinate = line.getOnStopPoiInfo.pt;

    item.title = line.tip;

    // NSLog(@”2222  %@”,line.tip);//上车信息,和下车信息加入数组的速度会配合,按顺序加入,不用考虑顺序问题

    [pathArray addObject:line.tip];

    if (line.type == 0) {

    item.type = 2;

    } else {

    item.type = 3;

    }

    [mapView addAnnotation:item];

    [item release];

    route = [plan.routes objectAtIndex:i+1];

    item = [[RouteAnnotation alloc]init];

    item.coordinate = line.getOffStopPoiInfo.pt;

    item.title = route.tip;

    // NSLog(@”2222  %@”,line.tip);

    // NSLog(@”3333  %@”,item.title);//下车信息

    [pathArray addObject:item.title];

    if (line.type == 0) {

    item.type = 2;

    } else {

    item.type = 3;

    }

    [mapView addAnnotation:item];

    [item release];

    if (i == size – 1) {

    i++;

    route = [plan.routes objectAtIndex:i];

    for (int j = 0; j < route.pointsCount; j++) {

    int len = [route getPointsNum:j];

    BMKMapPoint* pointArray = (BMKMapPoint*)[route getPoints:j];

    memcpy(points + index, pointArray, len * sizeof(BMKMapPoint));

    index += len;

    }

    break;

    }

    }

    BMKPolyline* polyLine = [BMKPolyline polylineWithPoints:points count:index];

    [mapView addOverlay:polyLine];

    delete []points;

    for (NSString *string in pathArray) {

    NSLog(@”bus %@”,string);

    }

    }

    }

    注:火星坐标系统貌似只对获取的坐标有修正,对地图可见的内容,如大头针没有修正,测试可见路线起点是正确的定位位置,虽然由经纬度得到的街道信息确实是偏移的,可能地图又再次做了修正

    关于从当前位置到目标的路线图,我做的处理就是定位按钮点击后,把现在位置的坐标传给了起始点然后在通过公交线路和驾车线路来实现线路的查询.

    相关文章

      网友评论

          本文标题:iOS 百度地图方便Mac下打开

          本文链接:https://www.haomeiwen.com/subject/sqpdbktx.html