iOS地圖找房(類似鏈家、安居客等地圖找房)

題外話:在百度搜索鍵入:iOS地圖找房泳梆。你會發(fā)現(xiàn)搜索到很多關于這方面的帖子鳖悠,但是幾乎都是詢問如何實現(xiàn)的,找不到一個可以研究借鑒的博客优妙。于是我決定補上這個空缺竞穷,寫的可能不全面,大家體諒鳞溉。

更新PS:原本我是沒打算寫Demo出來的瘾带,但博客發(fā)出來后很多人要,因為網(wǎng)絡請求不能發(fā)出來熟菲,請理解看政。我把Demo中的網(wǎng)絡請求全部干掉了,真正做這個項目的可以加入網(wǎng)絡請求抄罕,或者花點功夫模擬請求允蚣。最后如果覺得有用給個關注或喜歡,謝謝呆贿。

先看下美工出的效果圖嚷兔。
地圖找房_PxCook.png
下面說說實現(xiàn)的步驟森渐,仍然以代碼加注解的方式說明。我盡量說的詳盡冒晰,其實這個模塊難度一般同衣,應該很好理解的,如果有看不懂的給我留言就行了壶运。
分析:第一次進地圖要添加很多圓形的大區(qū)標識耐齐,這時候比例尺應該是整個市區(qū)的大小。當點擊這個圓形蒋情,可以進去小區(qū)的房源埠况,這個房源是一個消息框形式的標識,當比例尺在大區(qū)棵癣,地圖移動的時候應該是不允許在更新房源的辕翰,當小區(qū)的時候,需要更新狈谊,而且我們猜測這個更新不能太頻繁喜命,可能我們需要設定一個移動距離。同時的畴,大小區(qū)的切換渊抄,地圖放大到某個比例尺切換至小區(qū)尝胆,地圖縮小丧裁,切換到大區(qū)。

需要做的事情:定義兩種標識含衔。添加大區(qū)煎娇、小區(qū)標識。放大縮小后贪染,大小區(qū)的判斷顯示缓呛。移動地圖大小區(qū)的更新。點擊大小區(qū)不同的響應杭隙。
文末我會放上效果GIF哟绊。
首先,創(chuàng)建地圖痰憎,設置比例尺票髓,定位個人位置。比例尺的設定說明下铣耘,我這里給了一個自己定義的范圍洽沟,因為我不希望用戶無限放大地圖或者無限縮小。最小我希望他看到小區(qū)的大小即可蜗细,最大差不多展示整個南京市即可裆操。

  
    self.mapView = [[BMKMapView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight)];
    [self.view addSubview:self.mapView];
    self.locService = [[BMKLocationService alloc] init];
    self.mapView.delegate = self;
    self.locService.delegate = self;
    self.mapView.showsUserLocation = YES;
    self.mapView.showMapScaleBar = YES;//顯示比例尺
    self.mapView.mapScaleBarPosition = CGPointMake(10, 75);//比例尺位置
    self.mapView.minZoomLevel = 11;
    self.mapView.maxZoomLevel = 17;
    self.mapView.userTrackingMode = BMKUserTrackingModeNone;
    [self.locService startUserLocationService];

從效果圖中大家能夠看出怒详,一共兩個大頭針樣式,一個圓形的踪区,一個是對話框形式昆烁。你可以理解為這就是一個大頭針,只不過是換了圖片而已朽缴,那么如何定義自己想要的樣式呢善玫?
首先定義一個圓形的大頭針,可能需要主標題和副標題

image.png
#import <BaiduMapAPI_Map/BMKMapComponent.h>

@interface YLRoundAnnotationView : BMKAnnotationView
@property(nonatomic, strong) NSString *title;
@property(nonatomic, strong) NSString *subTitle;
@end

.m中去實現(xiàn)外觀的定義

@interface YLRoundAnnotationView ()
@property(nonatomic, strong) UILabel *titleLabel;
@property(nonatomic, strong) UILabel *subTitleLabel;

@end

@implementation YLRoundAnnotationView

- (id)initWithAnnotation:(id<BMKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier {
    if (self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier]) {
        [self setBounds:CGRectMake(0.f, 0.f, 80, 80)];
        [self setContentView];
    }
    return self;
}

- (void)setContentView {

    UIColor *color = [UIColor colorWithRed:234/255. green:130/255. blue:80/255. alpha:1];
    self.layer.cornerRadius = 40;
    self.layer.borderColor = color.CGColor;
    self.layer.borderWidth = 1;
    self.layer.masksToBounds = YES;
    self.backgroundColor = color;
    self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 5, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame)/2.5)];
    self.titleLabel.textAlignment = NSTextAlignmentCenter;
    self.titleLabel.font = font(15);
    self.titleLabel.textColor = [UIColor whiteColor];
    self.titleLabel.layer.masksToBounds = YES;
    [self addSubview:self.titleLabel];
   
    self.subTitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(self.titleLabel.frame), CGRectGetWidth(self.frame), CGRectGetHeight(self.frame)/3)];
    
    self.subTitleLabel.textAlignment = NSTextAlignmentCenter;
    self.subTitleLabel.font = font(13);
    self.subTitleLabel.textColor = [UIColor whiteColor];
    self.subTitleLabel.layer.masksToBounds = YES;
    [self addSubview:self.subTitleLabel];
}

- (void)setTitle:(NSString *)title {
    _title = title;
    self.titleLabel.text = title;
}
- (void)setSubTitle:(NSString *)subTitle {
    _subTitle = subTitle;
    self.subTitleLabel.text = subTitle;
}

上面我們重寫了大頭針的bound設置了圓角密强,然后在里面添加了兩個標題茅郎。
下面我們定義第二個大頭針,消息框模式的或渤。仍舊仿造上面代碼...

image.png

.h


#import <BaiduMapAPI_Map/BMKMapComponent.h>

@interface YLMessageAnnotationView : BMKAnnotationView
@property(nonatomic, strong) NSString *title;
@end

.m

@interface YLMessageAnnotationView ()
@property(nonatomic, strong) UIButton *contentView;

@end

@implementation YLMessageAnnotationView

- (id)initWithAnnotation:(id<BMKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier {
    if (self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier]) {
        [self setBounds:CGRectMake(0.f, 0.f, 80, 30)];
        [self setContentView];
    }
    return self;
}

- (void)setContentView {

    self.contentView = [UIButton buttonWithType:UIButtonTypeCustom];
    self.contentView.frame = self.bounds;
    self.contentView.userInteractionEnabled = NO;
    self.contentView.titleLabel.textAlignment = NSTextAlignmentCenter;
    [self.contentView setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    [self.contentView setBackgroundImage:[UIImage imageNamed:@"community"] forState:UIControlStateNormal];
    self.contentView.titleEdgeInsets = UIEdgeInsetsMake(-5, 0, 0, 0);
    self.contentView.titleLabel.font = font(10);
    [self addSubview:self.contentView];

}
- (void)setTitle:(NSString *)title {
    _title = title;
    [self.contentView setTitle:title forState:UIControlStateNormal];
}

為什么放一個Button系冗,因為方便標題和背景設置...
ok 定義完成械荷。我們就可以去網(wǎng)絡請求添加大頭針了浸踩。
如何添加,兩種情況:當比例尺很大的時候請求一種大頭針蠢熄,小的時候另一種大頭針

- (void)mapView:(BMKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {

    NSLog(@"更改了區(qū)域");
    NSLog(@"當前比例尺%f池磁,過去比例尺:%f",mapView.zoomLevel,self.zoomValue);
//    NSLog(@"中心點經(jīng)緯度 :%f,%f",mapView.centerCoordinate.latitude,mapView.centerCoordinate.longitude);
    
    if (mapView.zoomLevel > self.zoomValue) {
        NSLog(@"地圖放大了");
    }else if (mapView.zoomLevel < self.zoomValue){
        NSLog(@"地圖縮小了");
    }
    
    if (mapView.zoomLevel > 14) {
        //請求小區(qū)
        //當沒有放大縮小 計算平移的距離奔害。當距離小于2千米。不再進行計算  避免過度消耗
        float distance = [self distanceBetweenFromCoor:self.oldCoor toCoor:mapView.centerCoordinate];
        if (distance <= 1000 && mapView.zoomLevel == self.zoomValue) {
            return;
        }
        [self loadCityAreaHouseWithScale:@"1000" andLatitude:[NSString stringWithFormat:@"%f",mapView.centerCoordinate.latitude]  andLongitude:[NSString stringWithFormat:@"%f",mapView.centerCoordinate.longitude] andHouseType:self.houseType andRentType:self.rentType andHouseSize:self.houseSize andMinPrice:self.minPrice andMaxPrice:self.maxPrice];

    }else if(mapView.zoomLevel <= 14) {
        if (mapView.zoomLevel == self.zoomValue) {//當平移地圖地熄。大區(qū)不再重復請求
            return;
        }
        //請求大區(qū)
        [self loadCityAreaHouseWithScale:@"3000" andLatitude:@"" andLongitude:@"" andHouseType:self.houseType andRentType:self.rentType andHouseSize:self.houseSize andMinPrice:self.minPrice andMaxPrice:self.maxPrice];
    }
}

在上面這個代理方法中华临,當比例尺大于14我請求小區(qū)的房源。而且我做了個判斷端考,當沒有放大縮小 計算平移的距離雅潭。當距離小于2千米。不再進行計算 避免過度消耗却特。當比例尺小于等于14我請求大區(qū)的房源扶供。而且當?shù)貓D平移的時候,不再請求裂明。如何判斷地圖是否平移和平移后的距離椿浓?根據(jù)上面if再看下面代碼就明白了

- (void)mapView:(BMKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
    self.zoomValue = mapView.zoomLevel;
    self.oldCoor = mapView.centerCoordinate;
    NSLog(@"之前的比例尺:%f",mapView.zoomLevel);
}

如上,通過地圖移動前的中心點經(jīng)緯度和比例尺去與移動后的做比較即可闽晦。
下面看下網(wǎng)絡請求的代碼

//請求城市區(qū)域內的房源組
- (void)loadCityAreaHouseWithScale:(NSString *)scale andLatitude:(NSString *)latitude andLongitude:(NSString *)longitude andHouseType:(NSString *)houseType andRentType:(NSString *)rentType andHouseSize:(NSString *)houseSize andMinPrice:(NSString *)minPrice andMaxPrice:(NSString *)maxPrice {
    WeakSelf
    [SVProgressHUD show];
    [MapFindHouseViewModel mapFindHouseWithLatitude:latitude andLongitude:longitude andScale:scale andHouseType:houseType andRentType:rentType andHouseSize:houseSize andMinPrice:minPrice andMaxPrice:maxPrice andBlock:^(id result) {
        NSArray *data = result;
        if (data.count > 0) {
            [weakSelf.mapView removeAnnotations:weakSelf.mapView.annotations];
            if ([scale isEqualToString:@"3000"]) {//請求大區(qū)
                for (NSDictionary *dic in data) {
                    YLAnnotationView *an = [[YLAnnotationView alloc] init];
                    CLLocationCoordinate2D coor;
                    coor.latitude = [dic[@"lat"] floatValue];
                    coor.longitude = [dic[@"lng"] floatValue];
                    an.type = 1;
                    an.coordinate = coor;
                    an.title = dic[@"description"];
                    an.subtitle = [NSString stringWithFormat:@"%@套",dic[@"houses"]];
                    an.Id = dic[@"id"];
                    [weakSelf.mapView addAnnotation:an];
                }

            }else if([scale isEqualToString:@"1000"]) {//請求小區(qū)
                for (NSDictionary *dic in data) {
                    YLAnnotationView *an = [[YLAnnotationView alloc] init];
                    CLLocationCoordinate2D coor;
                    coor.latitude = [dic[@"lat"] floatValue];
                    coor.longitude = [dic[@"lng"] floatValue];
                    an.type = 2;
                    an.coordinate = coor;
                    an.title = [NSString stringWithFormat:@"%@ | %@套",dic[@"description"],dic[@"houses"]];
                    an.Id = dic[@"id"];
                    [weakSelf.mapView addAnnotation:an];
                }
            }
        }else {
            [SVProgressHUD showInfoWithStatus:@"無房源!請更改條件~"];
        }
    }];
}

前面我傳進來一個scale來標明到底是大區(qū)還是小區(qū)扳碍。3000代表大區(qū),反之小區(qū)尼荆。然后解析數(shù)據(jù)用一個大頭針模型YLAnnotationView 來接收左腔。最終把大頭針模型加入地圖。這時候就會走大頭針的數(shù)據(jù)源方法了捅儒。如下:

- (BMKAnnotationView *)mapView:(BMKMapView *)view viewForAnnotation:(id <BMKAnnotation>)annotation {
    // 生成重用標示identifier
    YLAnnotationView *anno = (YLAnnotationView *)annotation;
    if (anno.type == 1) {
        NSString *AnnotationViewID = @"round";
        // 檢查是否有重用的緩存
        YLRoundAnnotationView *annotationView = (YLRoundAnnotationView *)[view dequeueReusableAnnotationViewWithIdentifier:AnnotationViewID];
        
        // 緩存沒有命中液样,自己構造一個振亮,一般首次添加annotation代碼會運行到此處
        if (annotationView == nil) {
            annotationView = [[YLRoundAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID];
            annotationView.paopaoView = nil;
        }
        // 設置偏移位置
        annotationView.centerOffset = CGPointMake(0, -(annotationView.frame.size.height * 0.5));
        annotationView.title = anno.title;
        annotationView.subTitle = anno.subtitle;
        annotationView.annotation = anno;
        annotationView.canShowCallout = NO;
        return annotationView;
        
    }else {
        
        NSString *AnnotationViewID = @"message";
        // 檢查是否有重用的緩存
        YLMessageAnnotationView *annotationView = (YLMessageAnnotationView *)[view dequeueReusableAnnotationViewWithIdentifier:AnnotationViewID];
        // 緩存沒有命中,自己構造一個鞭莽,一般首次添加annotation代碼會運行到此處
        if (annotationView == nil) {
            annotationView = [[YLMessageAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID];
            annotationView.paopaoView = nil;
        }
        // 設置偏移位置
        annotationView.centerOffset = CGPointMake(0, -(annotationView.frame.size.height * 0.5));
        annotationView.title = anno.title;
        annotationView.annotation = anno;
        annotationView.canShowCallout = NO;
        return annotationView;
    }
}

在網(wǎng)絡請求哪里我給不同區(qū)域請求設置了type坊秸。這里正好用來判斷大頭針的顯示。這樣就做好了區(qū)別
最后你可能需要為這個大頭針添加點擊事件澎怒,那么只需要實現(xiàn)這個代理方法


//點擊了大頭針
- (void)mapView:(BMKMapView *)mapView didSelectAnnotationView:(BMKAnnotationView *)view {
    if (view.annotation.coordinate.latitude == self.locService.userLocation.location.coordinate.latitude) {//個人位置特殊處理褒搔,否則類型不匹配崩潰
        NSLog(@"點擊了個人位置");
        return;
    }
    YLAnnotationView *annotationView = (YLAnnotationView *)view.annotation;
    if (annotationView.type == 2) {
        self.areaTitle = annotationView.title;
        //取消大頭針的選中狀態(tài),否則下次再點擊同一個則無法響應事件
        [mapView deselectAnnotation:annotationView animated:NO];
        //計算距離 --> 請求列表數(shù)據(jù) --> 完成 --> 展示表格
        self.communityId = annotationView.Id;
        //計算小區(qū)到個人位置的距離
        self.distanceText = [NSString stringWithFormat:@"離我:%.1fkm",[self distanceBetweenFromCoor:annotationView.coordinate toCoor:self.locService.userLocation.location.coordinate] / 1000];
        [self loadNewListData];
    }else {
        //點擊了區(qū)域--->進入小區(qū)
        //拿到大頭針經(jīng)緯度喷面,放大地圖星瘾。然后重新計算小區(qū)
        [mapView setCenterCoordinate:annotationView.coordinate animated:NO];
        [mapView setZoomLevel:16];
    }
}

在上面我做了一個特殊判斷,點擊個人位置直接return了惧辈。如果不這樣可能會程序crash琳状。點擊小區(qū)我彈出一個房源列表,點擊大區(qū)盒齿,我先移動地圖中心點到點擊的位置念逞,再把地圖放大。注意這個順序边翁,而且必須不能使用動畫翎承。
基本上核心代碼就這些了,當然我還做了很多別的功能符匾,例如搜索和檢索等...附加功能不再說明叨咖。

結語:其實這個功能本身應該是使用百度地圖的 高聚合 功能,有興趣的同學可以去了解這個功能待讳,但是就實際而言芒澜,這樣重寫大頭針更好一些仰剿。

最后上個效果圖吧!
iOS技術交流群:511860085 歡迎加入创淡!

.jpg
Untitled,南吮,d jjj.gif
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末琳彩,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子部凑,更是在濱河造成了極大的恐慌露乏,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涂邀,死亡現(xiàn)場離奇詭異瘟仿,居然都是意外死亡,警方通過查閱死者的電腦和手機比勉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門劳较,熙熙樓的掌柜王于貴愁眉苦臉地迎上來驹止,“玉大人,你說我怎么就攤上這事观蜗‰担” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵墓捻,是天一觀的道長抖仅。 經(jīng)常有香客問我,道長砖第,這世上最難降的妖魔是什么撤卢? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮梧兼,結果婚禮上凸丸,老公的妹妹穿的比我還像新娘。我一直安慰自己袱院,他們只是感情好屎慢,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著忽洛,像睡著了一般腻惠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上欲虚,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天集灌,我揣著相機與錄音,去河邊找鬼复哆。 笑死欣喧,一個胖子當著我的面吹牛,可吹牛的內容都是我干的梯找。 我是一名探鬼主播唆阿,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼锈锤!你這毒婦竟也來了驯鳖?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤久免,失蹤者是張志新(化名)和其女友劉穎浅辙,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體阎姥,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡记舆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了呼巴。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泽腮。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡泊愧,死狀恐怖,靈堂內的尸體忽然破棺而出盛正,到底是詐尸還是另有隱情删咱,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布豪筝,位于F島的核電站痰滋,受9級特大地震影響,放射性物質發(fā)生泄漏续崖。R本人自食惡果不足惜敲街,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望严望。 院中可真熱鬧多艇,春花似錦、人聲如沸像吻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拨匆。三九已至姆涩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間惭每,已是汗流浹背骨饿。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留台腥,地道東北人宏赘。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像黎侈,于是被迫代替她去往敵國和親察署。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內容