iOS MapKit的使用-LBS简单的租车主界面demo
来源:互联网 发布:干了这碗恒河水 知乎 编辑:程序博客网 时间:2024/05/16 14:20
效果
分析
三个view:地图view、车辆信息view、车辆类型选择view
- 地图view:大头针的摆放,根据不同的种类显示大头针
- 车辆信息view:根据当前点击的大头针显示对应的车辆信息
- 车辆类型选择view:选择车辆类型
交互分析
- 选择车辆类型,地图上出现不同的大头针
- 车辆信息view可滑动,滑动完成后地图定位到当前车辆的大头针上
view的搭建
- 车辆选择view:自定义slider 分段滑竿(上一篇文章提到过)
- 车辆信息View:使用uicollectionView的流水布局,做出分页效果
- mapView:自定义大头针,根据类型选择不同的大头针图片
- 参数的传递
- 模拟数据通过编写1.plist完成
- 读取plist数据,通过选择车辆类型,将筛选出来的数据使用模型数组存放,通过set方法传递给mapView和车辆信息view,并刷新界面
- 选择车辆信息view 通过代理将当前显示的车辆信息页传递给mapview并定位
- mapview有两个委托方法,
点击空白处
和点击大头针
两个方法,用来设置车辆选择view和车辆信息view的显隐
代码
数据模型
- 数据模型及KVC使用
#import <Foundation>//车类型typedef NS_ENUM(NSInteger, CarType) { CarTypeNone = -1, //默认大头针 CarTypeDaily, //日租 CarTypeHourly, //时租 CarTypeLong, //长租 CarTypeTestDrive, //试驾};@interface CarModel : NSObject@property(nonatomic,strong)NSDictionary *location; //经纬度@property(nonatomic,assign)NSString *carType; //车类型@property(nonatomic,copy)NSString *carName; //车名称@property(nonatomic,copy)NSString *price; //价格@property(nonatomic,copy)NSString *distance; //与用户的距离@property(nonatomic,copy)NSString *locationName; //当前位置名@property(nonatomic,copy)NSString *imageName; //车图片@property(nonatomic,copy)NSString *order; //订单@property(nonatomic,copy)NSString *banDay; //限行- (instancetype)initWithCarModelDict:(NSDictionary*)dict;+ (instancetype)carModelWithDict:(NSDictionary*)ditc;@end
自定义collectionview
使用xib的约束直接布局cell,cell外部公开carModel,用于赋值
- 给自定义的collectionview写一个委托,用来告诉controller当前选择cellitem
#import <UIKit>#import "CarModel.h"@protocol CarInfoCollectionViewDelegate <NSObject>- (void)selectItemArray:(NSArray*)array WithIndex:(NSInteger)index;@end@interface CarInfoCollectionView : UICollectionView@property (nonatomic,strong)NSMutableArray<CarModel> *carModelArray;@property (nonatomic,strong)id<CarInfoCollectionViewDelegate> delegate2;@end
- 界面呈现翻页效果 左右两边留上一页和下一页的边缘,需要计算停下的位置,使用
UICollectionViewDelegate
代理方法
//停下的位置- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{ UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout*)self.collectionViewLayout; //实际滑动的距离 float pageWidth = layout.itemSize.width + layout.minimumLineSpacing; //当前位置 float currentOffset = scrollView.contentOffset.x; //目标位置 float targetOffset = targetContentOffset->x; float newTargetOffset = 0; int count = 0; if (targetOffset > currentOffset) { //向上取整 count = ceilf(currentOffset / pageWidth); newTargetOffset = ceilf(currentOffset / pageWidth) * pageWidth; }else { //向下取整 count = floorf(currentOffset / pageWidth); newTargetOffset = floorf(currentOffset / pageWidth) * pageWidth; } //处理边界 if (newTargetOffset < 0 xss=removed> scrollView.contentSize.width) newTargetOffset = scrollView.contentSize.width; //设置目标位置指针 targetContentOffset->x = currentOffset; //跳转新位置 [scrollView setContentOffset:CGPointMake(newTargetOffset, 0) animated:YES];}
- 当界面滚动完成时,通过代理通知controller当前的cellitem
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout*)self.collectionViewLayout; //实际滑动的距离 int pageWidth = layout.itemSize.width + layout.minimumLineSpacing; //当前位置 int currentOffset = scrollView.contentOffset.x; int count = currentOffset / pageWidth; NSLog(@"滚完了 %d",count ); if ([self.delegate2 respondsToSelector:@selector(selectItemArray:WithIndex:)]) { [self.delegate2 selectItemArray:self.carModelArray WithIndex:count]; }}
mapView
- 代理
#import <UIKit>#import <MapKit>#import "CarModel.h"@protocol MapViewDelegate <NSObject>//点击地图没有点到大头针- (void)didSelectMapWithoutAnnotation;//点到大头针- (void)didSelectMapAnnotationViewWithCarArray:(NSMutableArray<CarModel>*)carArray WithIndex:(NSInteger)index;@end@interface MapView : UIView@property(nonatomic,strong)id<MapViewDelegate> delegate;@property (nonatomic,strong)MKMapView *map;//大头针数组@property (nonatomic,strong)NSMutableArray *annotationArray;//car数据模型数组@property (nonatomic,strong)NSMutableArray<CarModel> *carModelArray;@end
- 使用到的全局变量
@interface MapView()<CLLocationManagerDelegate>@property (nonatomic,strong)CLLocationManager *locationManager;@property (nonatomic,strong)UIButton *currentLocationBtn;@property (nonatomic,strong)UIButton *zoomInBtn; //放大@property (nonatomic,strong)UIButton *zoomOutBtn;//缩小@property (nonatomic,strong)MyAnnotation *userLocationAnnotation;@property (nonatomic,assign)int scale;@end
- 初始化
//初始化- (instancetype)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { self.carModelArray = [NSMutableArray array]; [self loadingMapInfo]; [self addSubview:self.map]; [self addSubview:self.currentLocationBtn]; [self addSubview:self.zoomInBtn]; [self addSubview:self.zoomOutBtn]; } return self;}
- 全局变量使用懒加载 需要提到的是当前位置的大头针的位置需要进行火星转码
//当前位置大头针- (MyAnnotation *)userLocationAnnotation { if (!_userLocationAnnotation) { _userLocationAnnotation = [[MyAnnotation alloc] init]; _userLocationAnnotation.type = CarTypeNone; //转火星坐标 CLLocationCoordinate2D currentLocation = [WGS84TOGCJ02 transformFromWGSToGCJ:self.locationManager.location.coordinate]; _userLocationAnnotation.coordinate = currentLocation; _userLocationAnnotation.title = @"我的位置"; } return _userLocationAnnotation;}
- 定位当前位置和放大缩小按钮的实现
//定位- (UIButton *)currentLocationBtn { if (!_currentLocationBtn) { _currentLocationBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, CGRectGetHeight(self.frame)*0.6, 50, 50)]; [_currentLocationBtn setImage:[UIImage imageNamed:@"location_my.png"] forState:UIControlStateNormal]; [_currentLocationBtn addTarget:self action:@selector(clickCurrentBtn) forControlEvents:UIControlEventTouchUpInside]; } return _currentLocationBtn;}//点击定位- (void)clickCurrentBtn { [self.map deselectAnnotation:self.userLocationAnnotation animated:NO]; [self.map selectAnnotation:self.userLocationAnnotation animated:YES];}//放大- (UIButton *)zoomInBtn { if (!_zoomInBtn) { _zoomInBtn = [[UIButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.frame)-60, CGRectGetHeight(self.frame)*0.55, 50, 50)]; [_zoomInBtn setImage:[UIImage imageNamed:@"zoomin.png"] forState:UIControlStateNormal]; [_zoomInBtn addTarget:self action:@selector(mapZoomIn) forControlEvents:UIControlEventTouchUpInside]; } return _zoomInBtn;}//放大方法- (void)mapZoomIn { MKCoordinateRegion region = self.map.region; region.span.latitudeDelta = region.span.latitudeDelta * 0.5; region.span.longitudeDelta = region.span.longitudeDelta * 0.5; [self.map setRegion:region animated:YES];}//缩小- (UIButton *)zoomOutBtn { if (!_zoomOutBtn) { _zoomOutBtn = [[UIButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.frame)-60, CGRectGetMaxY(self.zoomInBtn.frame), 50, 50)]; [_zoomOutBtn setImage:[UIImage imageNamed:@"zoomout.png"] forState:UIControlStateNormal]; [_zoomOutBtn addTarget:self action:@selector(mapZoomOut) forControlEvents:UIControlEventTouchUpInside]; } return _zoomOutBtn;}//缩小方法- (void)mapZoomOut { MKCoordinateRegion region = self.map.region; region.span.latitudeDelta = region.span.latitudeDelta * 2; region.span.longitudeDelta = region.span.longitudeDelta * 2; [self.map setRegion:region animated:YES];}
- 授权使用定位功能 info.plist上添加
Privacy - Location Always Usage Description
值随便填
//获取授权- (void)getAuthorization { //获取授权状态 CLAuthorizationStatus status = [CLLocationManager authorizationStatus]; if (status == kCLAuthorizationStatusNotDetermined) { [self.locationManager requestAlwaysAuthorization]; } else if (status == kCLAuthorizationStatusAuthorizedAlways) { //不跟随用户 self.map.userTrackingMode = MKUserTrackingModeNone; }}//授权后进入- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{ //授权后开始定位 [self.locationManager startUpdatingLocation]; //加载地图信息 [self loadData]; [self loadingMapInfo];}
- 公开变量设置set方法用于刷新地图大头针信息
//set方法- (void)setCarModelArray:(NSMutableArray<CarModel> *)carModelArray { for (MyAnnotation *an in self.map.annotations) { if (an.type != CarTypeNone) { [self.map removeAnnotation:an]; } } [_carModelArray removeAllObjects]; _carModelArray = carModelArray; //重新加载数据 [self loadData];}//加载模拟数据- (void)loadData { [self.annotationArray removeAllObjects]; //完善model数据 for (CarModel *model in self.carModelArray) { CLGeocoder *coder = [[CLGeocoder alloc] init]; //model中的位置 CLLocation *location = [[CLLocation alloc] initWithLatitude:[model.location[@"lat"] doubleValue] longitude:[model.location[@"long"] doubleValue]]; //反地理编码 获得 经纬度 对应的 地名 并计算与当前位置的距离 [coder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark> * _Nullable placemarks, NSError * _Nullable error) { CLPlacemark *mark = [placemarks firstObject]; CLLocationCoordinate2D locatio = [WGS84TOGCJ02 transformFromWGSToGCJ:self.locationManager.location.coordinate]; CLLocation *currentLocation = [[CLLocation alloc] initWithLatitude:locatio.latitude longitude:locatio.longitude]; CLLocationDistance dis = [location distanceFromLocation:currentLocation]; model.locationName = mark.name; model.distance = [NSString stringWithFormat:@"%.2fkm",dis/1000]; }]; } int count = 0; //加载大头针 for (CarModel *model in self.carModelArray) { MyAnnotation *annotation = [[MyAnnotation alloc] init]; CLLocationCoordinate2D location = CLLocationCoordinate2DMake([model.location[@"lat"] doubleValue], [model.location[@"long"] doubleValue]); annotation.coordinate = location; annotation.index = count; annotation.type = [model.carType intValue]; [self.map addAnnotation:annotation]; [self.annotationArray addObject:annotation]; count++; }}
- mapview自身的代理方法,点击和取消大头针,实现回调跳转车辆信息view
#pragma mark - MKMapViewDelegate//点击大头针- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view { //重置汽车原来的颜色 NSArray *array = [mapView annotations]; for (MyAnnotation *an in array) { MKAnnotationView *v = [mapView viewForAnnotation:an]; if ([v.reuseIdentifier isEqualToString:@"carViewID"]) { v.image = [self getCarImageWithTypeInAnnotation:an]; } } //点击小车换颜色 if ([view.reuseIdentifier isEqualToString:@"carViewID"]) { view.image = [UIImage imageNamed:@"pickcar.png"]; //代理回调 通知界面 将 carInfoView 出现 carPickView消失 if ([self.delegate respondsToSelector:@selector(didSelectMapAnnotationViewWithCarArray:WithIndex:)]) { [self.delegate didSelectMapAnnotationViewWithCarArray:self.carModelArray WithIndex:((MyAnnotation*)view.annotation).index]; } //设置中心点和范围 [self.map setRegion:MKCoordinateRegionMakeWithDistance(((MyAnnotation*)view.annotation).coordinate, 2000, 2000) animated:NO]; } else { [self.map setRegion:MKCoordinateRegionMakeWithDistance(self.userLocationAnnotation.coordinate, 2000, 2000) animated:YES]; }}//没有选中大头针- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view { //重置汽车原来的颜色 NSArray *array = [mapView annotations]; for (MyAnnotation *an in array) { MKAnnotationView *v = [mapView viewForAnnotation:an]; if ([v.reuseIdentifier isEqualToString:@"carViewID"]) { v.image = [self getCarImageWithTypeInAnnotation:an]; } } if ([view.reuseIdentifier isEqualToString:@"carViewID"]) { //代理回调 通知界面 将 carInfoView 消失 carPickView出现 小车变为未选中 if ([self.delegate respondsToSelector:@selector(didSelectMapWithoutAnnotation)]) { [self.delegate didSelectMapWithoutAnnotation]; } }}
- 自定义大头针 当前位置使用标注 其他位置使用自定义的大头针视图
//当前位置大头针- (MKPinAnnotationView*)customLocalAnnotationView:(id<MKAnnotation>)annotation { static NSString *locationID = @"locationViewID"; //从缓存池中获取大头针 MKPinAnnotationView *pinView = ( MKPinAnnotationView *)[self.map dequeueReusableAnnotationViewWithIdentifier:locationID]; if (pinView == nil) { pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:locationID]; } pinView.annotation = annotation; // 取消气泡显示 pinView.canShowCallout = YES; // 设置大头针是否有下落动画 pinView.animatesDrop = YES; return pinView;}//自定义大头针- (MKAnnotationView*)customMKAnnotationView:(id<MKAnnotation>)annotation { //自定义大头针 static NSString *carViewID = @"carViewID"; //从缓存池中获取自定义大头针 MKAnnotationView *annoView = [self.map dequeueReusableAnnotationViewWithIdentifier:carViewID]; if (annoView == nil) { //缓存池中没有则创建 annoView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:carViewID]; } annoView.annotation = annotation; annoView.canShowCallout = NO; annoView.draggable = YES; annoView.image = [self getCarImageWithTypeInAnnotation:annotation]; return annoView;}//根据大头针的类型返回图片- (UIImage *)getCarImageWithTypeInAnnotation:(MyAnnotation*)annotation { switch (annotation.type) { case CarTypeDaily: return [UIImage imageNamed:@"dailycar.png"]; break; case CarTypeHourly: return [UIImage imageNamed:@"hourlycar.png"]; break; case CarTypeLong: return [UIImage imageNamed:@"longcar.png"]; break; case CarTypeTestDrive: return [UIImage imageNamed:@"testcar.png"]; break; default: break; } return nil;}
viewController主界面
- 将三个视图定义为全局 并使用懒加载 collectionView使用流水布局,为显示翻页效果需要配合增加头尾空白
- (CarInfoCollectionView *)collectionView { if (!_collectionView) { UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; layout.itemSize = CGSizeMake(kScreenWidth * 0.85, kScreenHeight*0.2); layout.minimumLineSpacing = kScreenWidth * 0.05; CGFloat referenceWidth = (kScreenWidth - layout.itemSize.width - 2*layout.minimumLineSpacing)/2 + layout.minimumLineSpacing; layout.headerReferenceSize = CGSizeMake(referenceWidth, 0); layout.footerReferenceSize = CGSizeMake(referenceWidth, 0); layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; _collectionView = [[CarInfoCollectionView alloc] initWithFrame:CGRectMake(0, kScreenHeight*0.8, self.view.frame.size.width, kScreenHeight*0.2) collectionViewLayout:layout]; _collectionView.hidden = YES; _collectionView.delegate2 = self; } return _collectionView;}
- (MapView *)mapView { if (!_mapView) { _mapView = [[MapView alloc] initWithFrame:self.view.bounds]; _mapView.delegate = self; } return _mapView;}- (CustomSlider *)carPickView { if (!_carPickView) { _carPickView = [[CustomSlider alloc] initWithFrame:CGRectMake(0, kScreenHeight*0.8, kScreenWidth, kScreenHeight*0.2)]; _carPickView.backgroundColor = [UIColor whiteColor]; _carPickView.sliderBarHeight = 10; _carPickView.numberOfPart = 4; _carPickView.partColor = [UIColor grayColor]; _carPickView.sliderColor = [UIColor grayColor]; _carPickView.thumbImage = [UIImage imageNamed:@"yuanxing.png"]; _carPickView.partNameOffset = CGPointMake(0, -30); _carPickView.thumbSize = CGSizeMake(50, 50); _carPickView.partSize = CGSizeMake(20, 20); _carPickView.partNameArray = @[@"日租",@"时租",@"长租",@"试驾"]; [_carPickView addTarget:self action:@selector(valuechange:) forControlEvents:UIControlEventValueChanged]; } return _carPickView;}- (void)viewDidLoad { [super viewDidLoad]; [self.view addSubview:self.mapView]; [self.view addSubview:self.collectionView]; [self.view addSubview:self.carPickView]; [self valuechange:self.carPickView];}
- 从plist中加载数据
- (NSMutableArray<CarModel> *) selectCarWithType:(CarType)type { NSMutableArray *resultArray = [NSMutableArray array]; //读取数据 NSString *path = [[NSBundle mainBundle] pathForResource:@"1" ofType:@"plist"]; NSArray *array = [NSArray arrayWithContentsOfFile:path]; //存数据 for (NSDictionary *dict in array) { CarModel *model = [CarModel carModelWithDict:dict]; if ([model.carType intValue] == type) { [resultArray addObject:model]; } } return resultArray;}
- 实现各种委托方法
- (void)valuechange:(CustomSlider*)sender { NSLog(@"%ld",(long)sender.value); self.mapView.carModelArray = [self selectCarWithType:sender.value]; NSLog(@"%@",self.mapView.carModelArray);}- (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated.}//collectionview 滚动结束后 调用- (void)selectItemArray:(NSArray *)array WithIndex:(NSInteger)index { MyAnnotation *an = self.mapView.annotationArray[index]; [self.mapView.map selectAnnotation:an animated:YES];}#pragma mark - mapViewDelegate//点击地图没有点到大头针- (void)didSelectMapWithoutAnnotation { self.carPickView.hidden = NO; self.collectionView.hidden = YES;}//点到大头针- (void)didSelectMapAnnotationViewWithCarArray:(NSMutableArray<CarModel> *)carArray WithIndex:(NSInteger)index { self.collectionView.carModelArray = carArray; NSLog(@"cararraycoutn = %lu",(unsigned long)carArray.count); //跳转到选择的车辆信息 [self.collectionView selectItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0] animated:YES scrollPosition:UICollectionViewScrollPositionCenteredHorizontally]; //出现车辆信息动画 self.carPickView.hidden = YES; self.collectionView.hidden = NO; }
demo地址
https://github.com/gongxiaokai/EasyCarDemo 简书地址http://www.jianshu.com/users/7897b0bd4a55/latest_articles
0 0
- iOS MapKit的使用-LBS简单的租车主界面demo
- Objective-C MapKit的使用-LBS简单的租车主界面demo
- iOS<MapKit/MapKit.h> MKMapView的简单使用
- iOS --- 地图框架MapKit的简单使用
- ios-MapKit的使用
- LBS简单的使用
- iOS中MapKit的使用
- iOS MapKit的基本使用
- iOS - MapKit地图的简单使用和定位
- MapKit 以及大头针的简单使用
- iOS-MapKit的使用笔记
- iOS中 CoreLocation 和 MapKit 的使用
- iOS菜鸟-使用MapKit和CoreLocation实现简单的导航画线
- mapKit的使用
- MapKit的基本使用
- MapKit的基本使用
- MapKit框架的使用
- MapKit框架的使用
- faster rcnn windows下配置(windows8.1+cuda6.5+opencv2.49+VS2013+caffe+matlabr2014a)
- 如何快速转载CSDN中的博客
- 第047 函数的使用 初步使用
- 8、旋转数组的最小数字
- CentOS 6.8 64bit 环境 初始化 MySQL 5.7.17成功示例(验证时间2017-01-08)
- iOS MapKit的使用-LBS简单的租车主界面demo
- php实现多语言排序(按各自排序习惯排序)
- Android 解码MediaCodec 播放H264 265
- Android 笔记 快捷方式 / 桌面小组件
- 【Android实战】----Android Retrofit2.1.0设置编码格式GBK
- 详解JavaScript正则表达式之RegExp对象
- bootstrap 帮助文档 本地化站点部署记录
- 简单的安卓记事本
- gns3配置