共享單車合集(首頁地圖篇)

自2014年共享單車出來以后共享單車熱門話題就一直沒有斷過拷泽,大家對共享單車的說法也是褒貶不一剪个,而對于從事iOS開發(fā)前兩天才拿畢業(yè)證的我來說徽曲,到目前為止我已經獨立開發(fā)完成了一套完整的共享單車iOS端APP园欣,從去年2016開始公司就開始著手做共享單車炕矮,也想從中分一勺羹朋譬。目前已經上架了4個APP(后面還有很長的隊排著等著提交審核)盐茎。基本上大致功能都一樣徙赢,換湯不換藥的那種字柠,有興趣的可以去AppStore下載一下(Camelbb、QFQ共享單車狡赐、小龍單車窑业、犀牛單車、咪吖共享單車...)

下面說一下做共享單車APP開發(fā)期間的心得吧


地圖

共享單車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{
   /// 如果沒有規(guī)劃路線則可以移動
    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.路徑規(guī)劃

路徑規(guī)劃

在當選中一個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;
                /* 出發(fā)點. */
                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];
路徑規(guī)劃成功與否
#pragma mark -------------------- 路徑規(guī)劃搜索回調 --------------------
// 成功
- (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];
    }
}

// 路徑規(guī)劃失敗
- (void)AMapSearchRequest:(id)request didFailWithError:(NSError *)error
{
    [self.loadingView removeFromSuperview];
    [LCProgressHUD showFailure:@"路徑規(guī)劃失敗"];
    // 回收位置西潘、預約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;
    
}

這樣主頁地圖的主要功能就完成了 更多的是對于這兩個功能根據(jù)不同情況下的設置和展示 這個就比較復雜了 我就不一一貼了 按照自己的需求去判斷就OK了

有興趣的可以關注我的GitHub,如果喜歡的請給個Star哥倔,有建議的歡迎大家指出秸架,謝謝

我是Renjiee 我要做最騷的程序猿??????

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市咆蒿,隨后出現(xiàn)的幾起案子东抹,更是在濱河造成了極大的恐慌,老刑警劉巖沃测,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缭黔,死亡現(xiàn)場離奇詭異,居然都是意外死亡蒂破,警方通過查閱死者的電腦和手機馏谨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來附迷,“玉大人惧互,你說我怎么就攤上這事±” “怎么了喊儡?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長稻据。 經常有香客問我艾猜,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任匆赃,我火速辦了婚禮淤毛,結果婚禮上,老公的妹妹穿的比我還像新娘算柳。我一直安慰自己低淡,他們只是感情好,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布瞬项。 她就那樣靜靜地躺著查牌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪滥壕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天兽泣,我揣著相機與錄音绎橘,去河邊找鬼。 笑死唠倦,一個胖子當著我的面吹牛称鳞,可吹牛的內容都是我干的。 我是一名探鬼主播稠鼻,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼冈止,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了候齿?” 一聲冷哼從身側響起熙暴,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎慌盯,沒想到半個月后周霉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡亚皂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年俱箱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片灭必。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡狞谱,死狀恐怖,靈堂內的尸體忽然破棺而出禁漓,到底是詐尸還是另有隱情跟衅,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布璃饱,位于F島的核電站与斤,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜撩穿,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一磷支、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧食寡,春花似錦雾狈、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至呻畸,卻和暖如春移盆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背伤为。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工咒循, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人绞愚。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓叙甸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親位衩。 傳聞我的和親對象是個殘疾皇子裆蒸,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內容