美文网首页iOS Developer学无止境
福州便民自行车地图app(基于百度地图iOS SDK) 一期开发

福州便民自行车地图app(基于百度地图iOS SDK) 一期开发

作者: 黑羽肃霜 | 来源:发表于2017-01-15 18:22 被阅读368次

    20170226
    因项目已准备上线,部分功能已更新。
    20170305
    (上线中遇到的坑)[http://www.jianshu.com/p/75cbea8f60ed]

    榕易骑.png

    前言

    开发这个app纯粹是为了兴趣和练手。目前没有上线,发出来纯粹是为了可以更好的交流。程序中有很多不成熟的地方,也希望看到的人可以批评指正。

    效果图

    效果图.gif

    百度地图的iOS SDK 及OC sample

    • 示例demo中针对每种功能都有一个单独的XIB及功能描述。
    • 我们需要用到的几个功能包括:
      • 基础的BMKMapView —— 百度地图中,最基础也是最重要的地图类。覆盖物的添加,标注的添加等等的代理回调,都与他相关
      • 区域搜索功能 —— 用于行政区域边界的绘制,绘制区域的覆盖物。
      • 定位功能 —— 用于定位当前位置
      • 路径规划功能 —— 暂时还未用到

    框架的搭建

    构想

    百度地图提供的每一个工具类,都有对应的代理。因为设计的页面(一期)只有一个ViewController,如果将所有的代理实现及功能都放在一起,代码会非常乱。

    管理地图的生命周期:自2.0.0起,BMKMapView新增viewWillAppear、viewWillDisappear方法来控制BMKMapView的生命周期,并且在一个时刻只能有一个BMKMapView接受回调消息,因此在使用BMKMapView的viewController中需要在viewWillAppear、viewWillDisappear方法中调用BMKMapView的对应的方法,并处理delegate,代码如下:

    (void)viewWillAppear:(BOOL)animated {      
        [_mapView viewWillAppear];      
        _mapView.delegate = self; // 此处记得不用的时候需要置nil,否则影响内存的释放      
    }      
    -(void)viewWillDisappear:(BOOL)animated {      
            [_mapView viewWillDisappear];      
          _mapView.delegate = nil; // 不用时,置nil      
    }
    

    百度工具类的单例实现

    • 根据上述的构想,将定位功能路径规划区域搜索功能都做成单例。在单例的调用中,放入基础的地图类BMKMapView类。单例的初始化可以写为
        [[BaiduLocationTool initInstanceWithMapView:self.BaseBaiduMapView] startLocation];
        // 默认画出鼓楼区的边界,设置district对应的delegate
        [BaiduDistrictTool initInstanceWithMapView:self.BaseBaiduMapView];
    
    • 设置代理和单例初始化的同时,要开启上述的地图管理生命周期。这里的做法,是用一个广播通知给每个工具类单例,控制各个工具类的代理开关。
        [[NSNotificationCenter defaultCenter] postNotificationName:BAIDU_DELEGATE_CTRL_RADIO
                                                            object:DELEGATE_ON];
    
    • 工具类的简述及对应方法(图)


      工具类流程图.png

    鉴权问题

    百度地图鉴权及数据申请顺序逻辑

    导航模式

    站点导航模式的逻辑说明

    框架综述

    上述的做法,主要是为了修改代理对应的工具时,便于维护和封装。


    页面上类的描述

    参考图
    • ViewController —— 整体的控局类。当Overlay(覆盖物)和Annotation(标注)添加入本类的BMKMapView时,会触发相应的代理。
      • MyPinAnnotationView 标注视图类。这里自定义后可以去替换他的背景图。
    • BottomDistrictView —— 底部栏,根据福州五区设置。在选择后会弹出。他包含以下几个subview:
      • tableview显示下部的站点列表
        • 我们的TableViewCell是自定义的Cell,包含三个部分,左侧的区域logo,中间的站点信息和右侧的出发按键(GotoView)
        • GotoView也是一个自定义的XIB,包括一个画好的轮子和一个按键
          自定义cell
      • 区域名按钮 —— DistrictButton,用于选择/切换行政区域。
        选中后,触发以下功能
        • 如果BottomDistrictView未弹出,那么弹出
        • 顶部一共有 6个,本身选中时会发送一个广播,让其他5个按键不处于选中状态(背景图及样式修改)
        • model中取出对应区域的站点信息数组,写入当前的tableview
        • model中取出对应区域的站点信息的经纬度,转化为一个标注数组annotation,通过代理传值发送给ViewController,让主页添加对应标注
        • 通过代理传值,将当前的区域名称发送给ViewController,让主页添加覆盖物overlays

    数据的存储

    app中有两种数据需要交互。

    • 站点信息,包括 站点名,所属行政区域,站点地址,站点的经纬度。
    • 行政区域边界的坐标。

    站点信息

    将站点信息存储成JSON格式,调试中的测试需要,将数据放至七牛云存储。获取一个URL.

    • 经纬度
      因并没有办法获取到完整的站点的经纬度列表,demo中用到的是自己写死的固定数据。在主页上添加一个tapGestureRecongnizer返回点击后的经纬度进行测试。如下:
    -(IBAction)fetchPoitCoordiate:(UITapGestureRecognizer *)sender {
        CGPoint point = [sender locationInView:self.BaseBaiduMapView];
        CLLocationCoordinate2D coo = [self.BaseBaiduMapView convertPoint:point toCoordinateFromView:self.BaseBaiduMapView];
        NSLog(@"经纬度:%lf, %lf", coo.longitude,  coo.latitude);
    }
    

    申请到的数据返回后,采用MJExtension作转化。因Xcode 8禁止了插件,所以我们无法使用JSONFormatt作快速转化。推荐使用一个第三方开发者写的mac appWHC_DataModelFactory,支持OCSwift

    app icon

    站点信息的类,包含有以下的方法。


    stationinfo class

    行政区域边界

    百度地图SDK中,行政区域的绘制是通过覆盖物来完成的。

    • 一般而言,这个数据不会经常变动,我这里采用的是将五个行政区域的边界,用plist存储成一个键值对。
      行政区域边界说明.png
    • 专门写了一个plistManager类来管理plist在沙盒中的存储。若读出的字典为空或对应路径的文件不存在,就调用BaiduMapTool类搜索边界数据,然后创建一个。
    • 拿到坐标信息后,去调用BaiduMapTool类中对应的方法,产生一个覆盖物对象。BaiduMapTool类中有一个接口
    @property (nonatomic,strong) NSMutableDictionary *districtPolyganDict; //存放区域overlay的字典
    

    键值对为: 区域名称 -> 覆盖物.
    将刚才获取到的覆盖物对象存入到对应的区域下。等待调用。
    需要注意的是,按键在调用“全市”这个需求的时候,我们需要的是将五个区的覆盖物拼接在一起,因此整个字典的分布为:

    xx区 -> 对应覆盖物对象
    xx区 -> 对应覆盖物对象
    ...
    全市 -> 上述覆盖物对象组成的数组


    主页和底部栏之间的数据交互方式

    本应用的设想是:
    主页和底部栏之间,通过代理交互数据,以下简称主页为A,底部栏View为B


    示意图
    • 主页和底部栏之间的数据交互顺序,其实分别遵循下图的左右两个部分。
      但是特别容易忽略的一点是,假设我们从A发起,一直执行到最后一条,选中了B的cell,那么B会继续循环执行右边的操作,造成这个过程一直在死循环。解决的方式是,在发送代理通知时,在各自的类中添加标志位,判断是手势出发的选中,还是传值执行代理时代码触发的选中。
      ![Uploading CD7983B696EFC3FC3A5C8846F9BD4CA9_264088.gif . . .]


      交互代理示意图.png

    还未完成的部分及疑问

    • 顶部栏的路径规划/搜索功能,设置功能,包括更新数据,设置偏好等。
    • 判断当前的位置是否处于五区内,若处于,显示当前位置半径xx公里内的自行车站点作为“附近站点”
    • 便民自行车官网上,可以观察到目前福州全市150多个站点的地理位置标注以及信息。在我打开网页的前端源代码时可以清楚的看到坐标点的信息。那么是否有办法通过搭建一个自己的前端,去“福州便民自行车”官网上爬取他相应的信息,生成json信息。这样我们的数据就不是死的固定数据,而是有一个前端逻辑做索引。

    Many thanks.
    2017.1.15

    相关文章

      网友评论

        本文标题:福州便民自行车地图app(基于百度地图iOS SDK) 一期开发

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