iOS开发技术分享程序员iOS学习笔记

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

2017-06-22  本文已影响1000人  Renjiee

自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 我要做最骚的程序猿👨‍💻‍

上一篇下一篇

猜你喜欢

热点阅读