共享单车合集(首页地图篇)

作者: Renjiee | 来源:发表于2017-06-22 16:23 被阅读1000次

    自2014年共享单车出来以后共享单车热门话题就一直没有断过,大家对共享单车的说法也是褒贬不一,而对于从事iOS开发前两天才拿毕业证的我来说,到目前为止我已经独立开发完成了一套完整的共享单车iOS端APP,从去年2016开始公司就开始着手做共享单车,也想从中分一勺羹。目前已经上架了4个APP(后面还有很长的队排着等着提交审核)。基本上大致功能都一样,换汤不换药的那种,有兴趣的可以去AppStore下载一下(Camelbb、QFQ共享单车、小龙单车、犀牛单车、咪吖共享单车...)

    下面说一下做共享单车APP开发期间的心得吧


    地图

    共享单车APP主要的界面就是地图,对此我们采用的是高德地图SDK
    关于高德地图的SDK配置我就不说了 百度一大把

    首先是对mapView的一个基本设置和初始化,这个我就不详细说了,按需求自己设置就行了
    然后就是搜索到附近的单车和一个可移动的大头针图标


    单车标识
    指定位置

    1.添加单车标识和指定位置

    首先我们通过后台传输给你的单车定位点去添加地图Maker(附近单车)
    #pragma mark -------------------- 查找周围单车 --------------------
    - (void)updatingDrivers
    {
        //获取UserDefault读取登录账户
        NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
        
        NSString * userIdDt = [userDefault objectForKey:@"userId"];
        
        NSString * startLatitude = [userDefault objectForKey:@"startLatitude"];
        NSString * startLongitude = [userDefault objectForKey:@"startLongitude"];
        if(userIdDt != nil){
            MACoordinateRegion region;
            _centerCoordinate = _mapView.region.center;
            region.center= _centerCoordinate;
            
            if(startLatitude != nil){
                
                CLLocationCoordinate2D startPlace;
                startPlace.latitude = startLatitude.floatValue;
                startPlace.longitude = startLongitude.floatValue;
                _centerCoordinate = startPlace;
            }
            
            MAMapRect rect = MAMapRectForCoordinateRegion(MACoordinateRegionMakeWithDistance(_centerCoordinate, latitudinalRangeMeters, longitudinalRangeMeters));
            if(rect.size.width > 0 && rect.size.height > 0) {
                [_bikeManager POSTNearbyBike:_centerCoordinate];
                [_bikeManager searchDriversWithinMapRect:rect];
            }
        }
    }
    
    #pragma mark - driversManager delegate
    
    - (void)searchDoneInMapRect:(MAMapRect)mapRect withDriversResult:(NSArray *)drivers timestamp:(NSTimeInterval)timestamp
    {
        self.subtitleAry = [NSMutableArray array];
        
        if(![self.ridingState isEqualToString:@"1"]){
            [_mapView removeAnnotations:_drivers];
            [self.bikeCoordinateArray removeAllObjects];
            NSMutableArray * currDrivers = [NSMutableArray arrayWithCapacity:[drivers count]];
            [drivers enumerateObjectsUsingBlock:^(Bike * obj, NSUInteger idx, BOOL *stop) {
                MAPointAnnotation * driver = [[MAPointAnnotation alloc] init];
                driver.coordinate = obj.coordinate;
                driver.subtitle = obj.idInfo;
                driver.title = (NSString*)RoutePlanningViewControllerDestinationTitle;
                
                NSLog(@"%@",driver.subtitle);
                [self.subtitleAry addObject:driver.subtitle];
                NSLog(@"%f",driver.coordinate.latitude);
                
                NSLog(@"%f",driver.coordinate.longitude);
                [currDrivers addObject:driver];
                self.bikes = [[CLLocation alloc] initWithLatitude:driver.coordinate.latitude longitude:driver.coordinate.longitude];
                
                [self.bikeCoordinateArray addObject:_bikes];
                NSLog(@"h");
            }];
            
            [_mapView addAnnotations:currDrivers];
            
            _drivers = currDrivers;
        }
    }
    
    其次我们设置一个可以移动的Maker(指定位置图标)
    - (void)initCenterView
    {
        self.centerAnnotationView = [[MAPointAnnotation alloc] init];
        self.centerAnnotationView.coordinate = _mapView.centerCoordinate;
        self.centerAnnotationView.title = @"指定地点";
    
        [_mapView addAnnotation:self.centerAnnotationView];
    }
    
    - (void)mapViewRegionChanged:(MAMapView *)mapView{
       /// 如果没有规划路线则可以移动
        if(self.isRoute == NO){
            self.centerAnnotationView.coordinate = _mapView.centerCoordinate;
        }
    }
    
    将单车标识和指定位置添加在地图上
    if ([[annotation title] isEqualToString:@"指定地点"])
            {
                annotationView.image = [UIImage imageNamed:@"指定地点"];
                //设置中心点偏移,使得标注底部中间点成为经纬度对应点
                annotationView.centerOffset = CGPointMake(0, -(CURRENT_SIZE(28)/2));
                annotationView.zIndex = 1;
                
    
                [annotationView.image setAccessibilityIdentifier:@"指定地点"];
                [_mapView bringSubviewToFront:annotationView];
                
                 return annotationView;
            }
    
    if (![annotation isKindOfClass:[MANaviAnnotation class]])
            {
                if(self.isRoute == YES && self.haveStart == YES && self.isPop == NO){
                    
                    return annotationView;
                }
                UIImage *image = [[UIImage alloc]init];
                NSLog(@"subtitle=====%@",annotation.subtitle);
                if(annotation.subtitle.integerValue == 0){
                    image = [UIImage imageNamed:@"单车标识"];
                }else{
                    image = [UIImage imageNamed:@"红包车辆标识"];
                }
                
                annotationView.image = image;
                annotationView.centerOffset = CGPointMake(0, -22);
                annotationView.canShowCallout = NO;
                
                [UIView animateWithDuration:0.3
                                      delay:0
                                    options:UIViewAnimationOptionCurveEaseOut
                                 animations:^{
                                     CGRect bounds = annotationView.bounds;
                                     bounds.size.height -=5;
                                     CGPoint center = annotationView.center;
                                     center.y += 5;
                                     [annotationView setCenter:center];
                                     [annotationView setBounds:bounds];
                                 }
                                 completion:nil];
                
                [UIView animateWithDuration:0.2
                                      delay:0
                                    options:UIViewAnimationOptionCurveEaseIn
                                 animations:^{
                                     CGRect bounds = annotationView.bounds;
                                     bounds.size.height +=5;
                                     CGPoint center = annotationView.center;
                                     center.y -= 5;
                                     [annotationView setCenter:center];
                                     [annotationView setBounds:bounds];
                                 }
                                 completion:nil];
            }
    

    2.路径规划

    路径规划

    在当选中一个annotation views时接口里

    - (void) mapView:(MAMapView *)mapView didSelectAnnotationView:(MAAnnotationView *)view{
    

    下面只贴出部分代码

    MAPointAnnotation *startAnnotation = [[MAPointAnnotation alloc] init];
                    if(self.startCoordinate.latitude == 0){
                        self.startCoordinate = _mapView.userLocation.location.coordinate;
                        startAnnotation.coordinate = _mapView.centerCoordinate;
                    }else{
                        startAnnotation.coordinate = self.startCoordinate;
                    }
                    startAnnotation.title      = (NSString*)RoutePlanningViewControllerStartTitle;
                    startAnnotation.subtitle   = [NSString stringWithFormat:@"{%f, %f}", self.startCoordinate.latitude, self.startCoordinate.longitude];
                    self.centerAnnotationView.coordinate = startAnnotation.coordinate;
                    
    //                [_mapView addAnnotation:self.centerAnnotationView];
                    
                    self.destinationCoordinate = view.annotation.coordinate;
                    
                    AMapWalkingRouteSearchRequest *navi = [[AMapWalkingRouteSearchRequest alloc] init];
                    navi.multipath = 0;
                    
                    
                    self.startPlace = self.startCoordinate;
                    /* 出发点. */
                    navi.origin = [AMapGeoPoint locationWithLatitude:self.centerAnnotationView.coordinate.latitude
                                                           longitude:self.centerAnnotationView.coordinate.longitude];
                    /* 目的地. */
                    navi.destination = [AMapGeoPoint locationWithLatitude:self.destinationCoordinate.latitude
                                                                longitude:self.destinationCoordinate.longitude];
                    
                    [self.search AMapWalkingRouteSearch:navi];
    
    路径规划成功与否
    #pragma mark -------------------- 路径规划搜索回调 --------------------
    // 成功
    - (void)onRouteSearchDone:(AMapRouteSearchBaseRequest *)request response:(AMapRouteSearchResponse *)response
    {
        //1.将两个经纬度点转成投影点
        MAMapPoint point1 = MAMapPointForCoordinate(CLLocationCoordinate2DMake(self.startCoordinate.latitude,self.startCoordinate.longitude));
        MAMapPoint point2 = MAMapPointForCoordinate(CLLocationCoordinate2DMake(self.destinationCoordinate.latitude,self.destinationCoordinate.longitude));
        //2.计算距离
        CLLocationDistance distance = MAMetersBetweenMapPoints(point1,point2);
        NSLog(@"%f",distance);
        // 距离
        self.bikeDistanceString = [[NSString alloc]initWithFormat:@"%.f",distance];
        
        self.popView.distanceLabel.text = self.bikeDistanceString;
        
        // 到达时间
        int date = distance/80;
        NSString * dateStr = [[NSString alloc]initWithFormat:@"%d",date];
        self.popView.dateLabel.text = dateStr;
        
        // 保存点击的单车距离到UserDefault 预约需要
        NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
        [userDefault setObject:self.bikeDistanceString forKey:@"bikeDistance"];
        [userDefault setObject:dateStr forKey:@"bikeDate"];
        
        [userDefault synchronize];
        
    //    [self.centerAnnotationView removeFromSuperview];
        // 移除弹窗
        [self.loadingView removeFromSuperview];
        
        if (response.route == nil)
        {
            return;
        }
        
        //解析response获取路径信息
        self.route = response.route;
        
        if (response.count > 0)
        {
            NSLog(@"%ld)",(long)response.count);
            [self presentCurrentCourse];
            //添加手势到对象
            [_mapView addGestureRecognizer:_tapGesture];
        }
    }
    
    // 路径规划失败
    - (void)AMapSearchRequest:(id)request didFailWithError:(NSError *)error
    {
        [self.loadingView removeFromSuperview];
        [LCProgressHUD showFailure:@"路径规划失败"];
        // 回收位置、预约view
    //    [_mapView removeAnnotation:self.centerAnnotationView];
        self.centerAnnotationView.coordinate = _mapView.centerCoordinate;
        self.isPop = NO;
        [AnimationManager DownToTopAnimation:self.locationView];
        [self.locationView removeFromSuperview];
        [AnimationManager DownToTopAnimation:self.popView];
        [self.popView removeFromSuperview];
        NSLog(@"Error: %@", error.domain);
    }
    
    展示路线方案
    /* 展示当前路线方案. */
    - (void)presentCurrentCourse
    {
        [self.naviRoute removeFromMapView];
        
            MAPointAnnotation *startAnnotation = [[MAPointAnnotation alloc] init];
            
            startAnnotation.coordinate = self.startCoordinate;
            startAnnotation.title      = (NSString*)RoutePlanningViewControllerStartTitle;
            startAnnotation.subtitle   = [NSString stringWithFormat:@"{%f, %f}", self.startCoordinate.latitude, self.startCoordinate.longitude];
            NSLog(@"%f",self.startAnnotation.coordinate.latitude);
            
            MAPointAnnotation *destinationAnnotation = [[MAPointAnnotation alloc] init];
            destinationAnnotation.coordinate = self.destinationCoordinate;
            destinationAnnotation.title      = (NSString*)RoutePlanningViewControllerDestinationTitle;
            self.destinationAnnotation = destinationAnnotation;
            
            MANaviAnnotationType type = MANaviAnnotationTypeWalking;
            self.naviRoute = [MANaviRoute naviRouteForPath:self.route.paths[0] withNaviType:type showTraffic:YES startPoint:[AMapGeoPoint locationWithLatitude:startAnnotation.coordinate.latitude longitude:startAnnotation.coordinate.longitude] endPoint:[AMapGeoPoint locationWithLatitude:self.destinationAnnotation.coordinate.latitude longitude:self.destinationAnnotation.coordinate.longitude]];
            [self.naviRoute addToMapView:_mapView];
            
            /* 缩放地图使其适应polylines的展示. */
            [_mapView setVisibleMapRect:[CommonUtility mapRectForOverlays:self.naviRoute.routePolylines]
                            edgePadding:UIEdgeInsetsMake(RoutePlanningPaddingEdge, RoutePlanningPaddingEdge, RoutePlanningPaddingEdge, RoutePlanningPaddingEdge)
                               animated:YES];
        
        
    }
    
    设置路线颜色
    // 设置路线颜色
    - (MAOverlayRenderer *)mapView:(MAMapView *)mapView rendererForOverlay:(id <MAOverlay>)overlay
    {
        
        if ([overlay isKindOfClass:[LineDashPolyline class]])
        {
            MAPolylineRenderer *polylineRenderer = [[MAPolylineRenderer alloc] initWithPolyline:((LineDashPolyline *)overlay).polyline];
            polylineRenderer.lineWidth   = 4;
            polylineRenderer.lineJoinType = kMALineJoinRound;
            polylineRenderer.lineCapType  = kMALineCapRound;
            
            polylineRenderer.strokeColor = KMainColor;
            
            return polylineRenderer;
        }
        if ([overlay isKindOfClass:[MANaviPolyline class]])
        {
            MANaviPolyline *naviPolyline = (MANaviPolyline *)overlay;
            MAPolylineRenderer *polylineRenderer = [[MAPolylineRenderer alloc] initWithPolyline:naviPolyline.polyline];
            
            polylineRenderer.lineWidth = 4;
            polylineRenderer.lineJoinType = kMALineJoinRound;
            polylineRenderer.lineCapType  = kMALineCapRound;
            
            
            if (naviPolyline.type == MANaviAnnotationTypeWalking)
            {
                polylineRenderer.strokeColor = KMainColor;
            }
            else if (naviPolyline.type == MANaviAnnotationTypeRailway)
            {
                polylineRenderer.strokeColor = KMainColor;
            }
            else
            {
                polylineRenderer.strokeColor = KMainColor;
            }
            
            return polylineRenderer;
        }
        if ([overlay isKindOfClass:[MAMultiPolyline class]])
        {
            MAMultiColoredPolylineRenderer * polylineRenderer = [[MAMultiColoredPolylineRenderer alloc] initWithMultiPolyline:overlay];
            
            polylineRenderer.lineWidth = 4;
            polylineRenderer.lineJoinType = kMALineJoinRound;
            polylineRenderer.lineCapType  = kMALineCapRound;
            
            polylineRenderer.strokeColors = [self.naviRoute.multiPolylineColors copy];
            polylineRenderer.gradient = YES;
            
            return polylineRenderer;
        }
        
        return nil;
        
    }
    

    这样主页地图的主要功能就完成了 更多的是对于这两个功能根据不同情况下的设置和展示 这个就比较复杂了 我就不一一贴了 按照自己的需求去判断就OK了

    有兴趣的可以关注我的GitHub,如果喜欢的请给个Star,有建议的欢迎大家指出,谢谢

    我是Renjiee 我要做最骚的程序猿👨‍💻‍

    相关文章

      网友评论

      • KevinChein:很用心~
        Renjiee:@KevinChein 谢谢
      • 缪雨轩:您好,可以加一下微信或者qq嘛,关于ios共享单车app开发这一块有些问题想咨询一下
      • 钱十六:你好可以留一个联系方式吗?有些问题希望得到你的帮助。
        Renjiee:@钱十六 243327737我的QQ
      • mymirror:针对于地图内存泄漏,你对这块有什么优化
        Renjiee:我使用的是高德地图,目前没有发现有内存泄露

      本文标题:共享单车合集(首页地图篇)

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