先看效果:
gif动画是在模拟器上录制,由于模拟器不能获取周围信息,所以一直在转菊花。要看实际效果需要真机查看。
步骤
-
添加库
MapKit.framework
。
-
打开地图功能。
代码实现。
- 在用户位置显示完成后添加一个固定的
ImageView
在地图正中间。
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
NSLog(@"userLocation:longitude:%f---latitude:%f",userLocation.location.coordinate.longitude,userLocation.location.coordinate.latitude);
if (!haveGetUserLocation) {
if (self.mapView.userLocationVisible) {
haveGetUserLocation = YES;
[self getAddressByLatitude:userLocation.coordinate.latitude longitude:userLocation.coordinate.longitude];
[self addCenterLocationViewWithCenterPoint:self.mapView.center];
}
}
}
-(void)addCenterLocationViewWithCenterPoint:(CGPoint)point
{
if (!imgView) {
imgView = [[UIImageView alloc]initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2, 100, 18, 38)];
imgView.center = point;
imgView.image = [UIImage imageNamed:@"map_location"];
imgView.center = self.mapView.center;
[self.view addSubview:imgView];
}
}
- 获取当前位置周围信息,苹果提供了一个请求方法,
MKLocalSearch
。其官方介绍为:
如果我们要搜索周围100米餐厅代码如下:
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(coordinate,100, 100);
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc]init];
request.region = region;
request.naturalLanguageQuery = @"Restaurants";
MKLocalSearch *localSearch = [[MKLocalSearch alloc]initWithRequest:request];
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error){
if (!error) {
//do something.
}else{
//do something.
}
}];
其中naturalLanguageQuery
就是要搜索的关键字,我试过的所有关键字有cafe, supermarket,village,Community,Shop,Restaurant,School,hospital,Company,Street,Convenience store,Shopping Centre,Place names,Hotel,Grocery store
每个关键字搜索返回结果只有10条,如果当前范围无搜索结果,则扩散搜索范围。如果你想列出周围所有相关位置信息,我认为需要尽可能的把所有的能够想到的关键字都举例出来进行搜索,搜索完成后进行经纬度比较然后刷选出范围内的相关位置。而且由于数据来源问题,很多位置信息都没有!当然如果你只兼容国内,还是使用百度或者腾讯地图算了。
- 根据经纬度获取位置相关信息。
CLLocation *location=[[CLLocation alloc]initWithLatitude:latitude longitude:longitude];
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
if (!error) {
dispatch_async(dispatch_get_main_queue(), ^{
//do something.
});
}else{
//do something.
}
}];
- 下落定位动画效果
imgView.center = CGPointMake(mapCenter.x, mapCenter.y-15);
[UIView animateWithDuration:0.2 animations:^{
imgView.center = mapCenter;
}completion:^(BOOL finished){
if (finished) {
[UIView animateWithDuration:0.05 animations:^{
imgView.transform = CGAffineTransformMakeScale(1.0, 0.8);
}completion:^(BOOL finished){
if (finished) {
[UIView animateWithDuration:0.1 animations:^{
imgView.transform = CGAffineTransformIdentity;
}];
}
}];
}
}];
这里我的思路是三个动画效果组合以达到大头针下落定位的效果。
- 获取用户滑动地图操作。
MKMapViewDelegate
中有个方法在滑动结束后可以回调如下所示:
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
因为回调是在展示的地图区域改变后调用,所以使用它有个缺点就是在最开始初始化地图并定位到用户所在位置时,它会被反复回调。所以很难确定用户是否是滑动。所以这里我们需要知道用户是否和地图有过滑动后导致它的回调。如何做呢?这里有两种方法以供参考。
方法一:这里你是否想起UIScrollView
,如果我们想获取touch
事件,我们应该怎么做,没错就是继承后重写touch
方法,然后把toush
事件传递下去。代码如下:
@implementation ZHMapView
#pragma mark - touchs
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
[[self nextResponder] touchesBegan:touches withEvent:event];
}
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
[[self nextResponder] touchesMoved:touches withEvent:event];
}
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
[[self nextResponder] touchesEnded:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event
{
[super touchesCancelled:touches withEvent:event];
[[self nextResponder]touchesCancelled:touches withEvent:event];
}
方法二:我在修改 navigationBar 底部线条颜色总结这篇文章中有用到查看View层次结构找到隐藏属性并对它进行操作。没错这里也是一样的道理,先看mapview层次结构例如如下所示:
这里我们可以发现
_MKMapContentView
里面有个手势数组,没错就是它了。我们获取它并对他进行操作,代码如下所示:
//打印完后我们发现有个View带有手势数组其类型为_MKMapContentView获取Span手势
for (UIView *view in self.mapView.subviews) {
NSString *viewName = NSStringFromClass([view class]);
if ([viewName isEqualToString:@"_MKMapContentView"]) {
UIView *contentView = view;//[self.mapView valueForKey:@"_contentView"];
for (UIGestureRecognizer *gestureRecognizer in contentView.gestureRecognizers) {
if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
[gestureRecognizer addTarget:self action:@selector(mapViewSpanGesture:)];
}
}
}
}
- 加载时
UITableView
顶部展示菊花展示,这个原理和我们做分页展示时,滑动到底部或顶部有个菊花展示的道理一样。代码如下
#pragma mark - Private Methods
-(void)resetTableHeadView
{
if (infoArray.count>0) {
self.showTableView.tableHeaderView = nil;
}else{
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 30.0)];
view.backgroundColor = self.showTableView.backgroundColor;
UIActivityIndicatorView *indicatorView = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
indicatorView.center = view.center;
[indicatorView startAnimating];
[view addSubview:indicatorView];
self.showTableView.tableHeaderView = view;
}
}
下载地址
GitHub