仿链家地图找房_iOS地图找房(类似链家、安居客等地图找房)
題外話:在百度搜索鍵入:iOS地圖找房。你會(huì)發(fā)現(xiàn)搜索到很多關(guān)于這方面的帖子,但是幾乎都是詢問(wèn)如何實(shí)現(xiàn)的,找不到一個(gè)可以研究借鑒的博客。于是我決定補(bǔ)上這個(gè)空缺,寫的可能不全面,大家體諒。
更新PS:原本我是沒(méi)打算寫Demo出來(lái)的,但博客發(fā)出來(lái)后很多人要,因?yàn)榫W(wǎng)絡(luò)請(qǐng)求不能發(fā)出來(lái),請(qǐng)理解。我把Demo中的網(wǎng)絡(luò)請(qǐng)求全部干掉了,真正做這個(gè)項(xiàng)目的可以加入網(wǎng)絡(luò)請(qǐng)求,或者花點(diǎn)功夫模擬請(qǐng)求。最后如果覺(jué)得有用給個(gè)關(guān)注或喜歡,謝謝。
先看下美工出的效果圖。
地圖找房_PxCook.png
下面說(shuō)說(shuō)實(shí)現(xiàn)的步驟,仍然以代碼加注解的方式說(shuō)明。我盡量說(shuō)的詳盡,其實(shí)這個(gè)模塊難度一般,應(yīng)該很好理解的,如果有看不懂的給我留言就行了。
分析:第一次進(jìn)地圖要添加很多圓形的大區(qū)標(biāo)識(shí),這時(shí)候比例尺應(yīng)該是整個(gè)市區(qū)的大小。當(dāng)點(diǎn)擊這個(gè)圓形,可以進(jìn)去小區(qū)的房源,這個(gè)房源是一個(gè)消息框形式的標(biāo)識(shí),當(dāng)比例尺在大區(qū),地圖移動(dòng)的時(shí)候應(yīng)該是不允許在更新房源的,當(dāng)小區(qū)的時(shí)候,需要更新,而且我們猜測(cè)這個(gè)更新不能太頻繁,可能我們需要設(shè)定一個(gè)移動(dòng)距離。同時(shí),大小區(qū)的切換,地圖放大到某個(gè)比例尺切換至小區(qū),地圖縮小,切換到大區(qū)。
需要做的事情:定義兩種標(biāo)識(shí)。添加大區(qū)、小區(qū)標(biāo)識(shí)。放大縮小后,大小區(qū)的判斷顯示。移動(dòng)地圖大小區(qū)的更新。點(diǎn)擊大小區(qū)不同的響應(yīng)。
文末我會(huì)放上效果GIF。
首先,創(chuàng)建地圖,設(shè)置比例尺,定位個(gè)人位置。比例尺的設(shè)定說(shuō)明下,我這里給了一個(gè)自己定義的范圍,因?yàn)槲也幌M脩魺o(wú)限放大地圖或者無(wú)限縮小。最小我希望他看到小區(qū)的大小即可,最大差不多展示整個(gè)南京市即可。
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];
從效果圖中大家能夠看出,一共兩個(gè)大頭針樣式,一個(gè)圓形的,一個(gè)是對(duì)話框形式。你可以理解為這就是一個(gè)大頭針,只不過(guò)是換了圖片而已,那么如何定義自己想要的樣式呢?
首先定義一個(gè)圓形的大頭針,可能需要主標(biāo)題和副標(biāo)題
image.png
#import
@interface YLRoundAnnotationView : BMKAnnotationView
@property(nonatomic, strong) NSString *title;
@property(nonatomic, strong) NSString *subTitle;
@end
.m中去實(shí)現(xiàn)外觀的定義
@interface YLRoundAnnotationView ()
@property(nonatomic, strong) UILabel *titleLabel;
@property(nonatomic, strong) UILabel *subTitleLabel;
@end
@implementation YLRoundAnnotationView
- (id)initWithAnnotation:(id)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設(shè)置了圓角,然后在里面添加了兩個(gè)標(biāo)題。
下面我們定義第二個(gè)大頭針,消息框模式的。仍舊仿造上面代碼...
image.png
.h
#import
@interface YLMessageAnnotationView : BMKAnnotationView
@property(nonatomic, strong) NSString *title;
@end
.m
@interface YLMessageAnnotationView ()
@property(nonatomic, strong) UIButton *contentView;
@end
@implementation YLMessageAnnotationView
- (id)initWithAnnotation:(id)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];
}
為什么放一個(gè)Button,因?yàn)榉奖銟?biāo)題和背景設(shè)置...
ok 定義完成。我們就可以去網(wǎng)絡(luò)請(qǐng)求添加大頭針了。
如何添加,兩種情況:當(dāng)比例尺很大的時(shí)候請(qǐng)求一種大頭針,小的時(shí)候另一種大頭針
- (void)mapView:(BMKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
NSLog(@"更改了區(qū)域");
NSLog(@"當(dāng)前比例尺%f,過(guò)去比例尺:%f",mapView.zoomLevel,self.zoomValue);
// NSLog(@"中心點(diǎn)經(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ǐng)求小區(qū)
//當(dāng)沒(méi)有放大縮小 計(jì)算平移的距離。當(dāng)距離小于2千米。不再進(jìn)行計(jì)算 避免過(guò)度消耗
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) {//當(dāng)平移地圖。大區(qū)不再重復(fù)請(qǐng)求
return;
}
//請(qǐng)求大區(qū)
[self loadCityAreaHouseWithScale:@"3000" andLatitude:@"" andLongitude:@"" andHouseType:self.houseType andRentType:self.rentType andHouseSize:self.houseSize andMinPrice:self.minPrice andMaxPrice:self.maxPrice];
}
}
在上面這個(gè)代理方法中,當(dāng)比例尺大于14我請(qǐng)求小區(qū)的房源。而且我做了個(gè)判斷,當(dāng)沒(méi)有放大縮小 計(jì)算平移的距離。當(dāng)距離小于2千米。不再進(jìn)行計(jì)算 避免過(guò)度消耗。當(dāng)比例尺小于等于14我請(qǐng)求大區(qū)的房源。而且當(dāng)?shù)貓D平移的時(shí)候,不再請(qǐng)求。如何判斷地圖是否平移和平移后的距離?根據(jù)上面if再看下面代碼就明白了
- (void)mapView:(BMKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
self.zoomValue = mapView.zoomLevel;
self.oldCoor = mapView.centerCoordinate;
NSLog(@"之前的比例尺:%f",mapView.zoomLevel);
}
如上,通過(guò)地圖移動(dòng)前的中心點(diǎn)經(jīng)緯度和比例尺去與移動(dòng)后的做比較即可。
下面看下網(wǎng)絡(luò)請(qǐng)求的代碼
//請(qǐng)求城市區(qū)域內(nèi)的房源組
- (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ǐng)求大區(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ǐng)求小區(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:@"無(wú)房源!請(qǐng)更改條件~"];
}
}];
}
前面我傳進(jìn)來(lái)一個(gè)scale來(lái)標(biāo)明到底是大區(qū)還是小區(qū)。3000代表大區(qū),反之小區(qū)。然后解析數(shù)據(jù)用一個(gè)大頭針模型YLAnnotationView 來(lái)接收。最終把大頭針模型加入地圖。這時(shí)候就會(huì)走大頭針的數(shù)據(jù)源方法了。如下:
- (BMKAnnotationView *)mapView:(BMKMapView *)view viewForAnnotation:(id )annotation {
// 生成重用標(biāo)示identifier
YLAnnotationView *anno = (YLAnnotationView *)annotation;
if (anno.type == 1) {
NSString *AnnotationViewID = @"round";
// 檢查是否有重用的緩存
YLRoundAnnotationView *annotationView = (YLRoundAnnotationView *)[view dequeueReusableAnnotationViewWithIdentifier:AnnotationViewID];
// 緩存沒(méi)有命中,自己構(gòu)造一個(gè),一般首次添加annotation代碼會(huì)運(yùn)行到此處
if (annotationView == nil) {
annotationView = [[YLRoundAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID];
annotationView.paopaoView = nil;
}
// 設(shè)置偏移位置
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];
// 緩存沒(méi)有命中,自己構(gòu)造一個(gè),一般首次添加annotation代碼會(huì)運(yùn)行到此處
if (annotationView == nil) {
annotationView = [[YLMessageAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID];
annotationView.paopaoView = nil;
}
// 設(shè)置偏移位置
annotationView.centerOffset = CGPointMake(0, -(annotationView.frame.size.height * 0.5));
annotationView.title = anno.title;
annotationView.annotation = anno;
annotationView.canShowCallout = NO;
return annotationView;
}
}
在網(wǎng)絡(luò)請(qǐng)求哪里我給不同區(qū)域請(qǐng)求設(shè)置了type。這里正好用來(lái)判斷大頭針的顯示。這樣就做好了區(qū)別
最后你可能需要為這個(gè)大頭針添加點(diǎn)擊事件,那么只需要實(shí)現(xiàn)這個(gè)代理方法
//點(diǎn)擊了大頭針
- (void)mapView:(BMKMapView *)mapView didSelectAnnotationView:(BMKAnnotationView *)view {
if (view.annotation.coordinate.latitude == self.locService.userLocation.location.coordinate.latitude) {//個(gè)人位置特殊處理,否則類型不匹配崩潰
NSLog(@"點(diǎn)擊了個(gè)人位置");
return;
}
YLAnnotationView *annotationView = (YLAnnotationView *)view.annotation;
if (annotationView.type == 2) {
self.areaTitle = annotationView.title;
//取消大頭針的選中狀態(tài),否則下次再點(diǎn)擊同一個(gè)則無(wú)法響應(yīng)事件
[mapView deselectAnnotation:annotationView animated:NO];
//計(jì)算距離 --> 請(qǐng)求列表數(shù)據(jù) --> 完成 --> 展示表格
self.communityId = annotationView.Id;
//計(jì)算小區(qū)到個(gè)人位置的距離
self.distanceText = [NSString stringWithFormat:@"離我:%.1fkm",[self distanceBetweenFromCoor:annotationView.coordinate toCoor:self.locService.userLocation.location.coordinate] / 1000];
[self loadNewListData];
}else {
//點(diǎn)擊了區(qū)域--->進(jìn)入小區(qū)
//拿到大頭針經(jīng)緯度,放大地圖。然后重新計(jì)算小區(qū)
[mapView setCenterCoordinate:annotationView.coordinate animated:NO];
[mapView setZoomLevel:16];
}
}
在上面我做了一個(gè)特殊判斷,點(diǎn)擊個(gè)人位置直接return了。如果不這樣可能會(huì)程序crash。點(diǎn)擊小區(qū)我彈出一個(gè)房源列表,點(diǎn)擊大區(qū),我先移動(dòng)地圖中心點(diǎn)到點(diǎn)擊的位置,再把地圖放大。注意這個(gè)順序,而且必須不能使用動(dòng)畫。
基本上核心代碼就這些了,當(dāng)然我還做了很多別的功能,例如搜索和檢索等...附加功能不再說(shuō)明。
結(jié)語(yǔ):其實(shí)這個(gè)功能本身應(yīng)該是使用百度地圖的 高聚合 功能,有興趣的同學(xué)可以去了解這個(gè)功能,但是就實(shí)際而言,這樣重寫大頭針更好一些。
最后上個(gè)效果圖吧!
iOS技術(shù)交流群:511860085 歡迎加入!
.jpg
Untitled,,d jjj.gif
總結(jié)
以上是生活随笔為你收集整理的仿链家地图找房_iOS地图找房(类似链家、安居客等地图找房)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Excel-VBA操作文件四大方法
- 下一篇: TapTap物理画线游戏,使用Unity