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