我寻觅了很多关于这个问题,但他们都不做的正是我想要的。 很多教程告诉我如何添加线条和多边形的代码,但不能与写意画。
现在的问题是下列之一:
我建立一个房地产应用。 如果用户是在MKMapView
它来绘制一个矩形/圆圈的能力/ ...大概只是他/她想要买/租到房子的某个区域。 然后我需要显示用户已选择的区域内对应的结果。
目前,我有一个UIView
我之上MKMapView
在那里我做了一些自定义绘制,有没有办法来翻译点从或坐标..? 或者,这是完全没有做到这一点的呢? 我也听说过MKMapOverlayView
等。但我不完全知道如何使用它。
任何人都可以点我在正确的方向或者他有一些示例代码或教程,可以帮助我完成我什么需要?
谢谢
我有一个应用程序,基本上做到这一点。 我有一个地图视图,在屏幕顶部的工具栏。 当您按下该工具栏上的按钮,你现在是在一个模式,你可以在地图上滑动手指。 开始和滑动的端将代表一个矩形的角。 该应用程序将绘制一个半透明的蓝色矩形覆盖,以显示您所选择的区域。 当你抬起手指,矩形选择完成,以及应用程序开始搜索在我的数据库位置。
我不处理的圈子,但我想你可以做同样的事情,你有两种选择模式(矩形或圆形)。 在圆形选择模式中,滑动开始和结束点可以表示圆心,和边缘(半径)。 或者说,一条直径线的两端。 我会离开的那部分给你。
履行
首先,我定义了一个透明覆盖层,用于处理选择(OverlaySelectionView.h):
#import <QuartzCore/QuartzCore.h>
#import <MapKit/MapKit.h>
@protocol OverlaySelectionViewDelegate
// callback when user finishes selecting map region
- (void) areaSelected: (CGRect)screenArea;
@end
@interface OverlaySelectionView : UIView {
@private
UIView* dragArea;
CGRect dragAreaBounds;
id<OverlaySelectionViewDelegate> delegate;
}
@property (nonatomic, assign) id<OverlaySelectionViewDelegate> delegate;
@end
和OverlaySelectionView.m:
#import "OverlaySelectionView.h"
@interface OverlaySelectionView()
@property (nonatomic, retain) UIView* dragArea;
@end
@implementation OverlaySelectionView
@synthesize dragArea;
@synthesize delegate;
- (void) initialize {
dragAreaBounds = CGRectMake(0, 0, 0, 0);
self.userInteractionEnabled = YES;
self.multipleTouchEnabled = NO;
self.backgroundColor = [UIColor clearColor];
self.opaque = NO;
self.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
}
- (id) initWithCoder: (NSCoder*) coder {
self = [super initWithCoder: coder];
if (self != nil) {
[self initialize];
}
return self;
}
- (id) initWithFrame: (CGRect) frame {
self = [super initWithFrame: frame];
if (self != nil) {
[self initialize];
}
return self;
}
- (void)drawRect:(CGRect)rect {
// do nothing
}
#pragma mark - Touch handling
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* touch = [[event allTouches] anyObject];
dragAreaBounds.origin = [touch locationInView:self];
}
- (void)handleTouch:(UIEvent *)event {
UITouch* touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:self];
dragAreaBounds.size.height = location.y - dragAreaBounds.origin.y;
dragAreaBounds.size.width = location.x - dragAreaBounds.origin.x;
if (self.dragArea == nil) {
UIView* area = [[UIView alloc] initWithFrame: dragAreaBounds];
area.backgroundColor = [UIColor blueColor];
area.opaque = NO;
area.alpha = 0.3f;
area.userInteractionEnabled = NO;
self.dragArea = area;
[self addSubview: self.dragArea];
[dragArea release];
} else {
self.dragArea.frame = dragAreaBounds;
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[self handleTouch: event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[self handleTouch: event];
if (self.delegate != nil) {
[delegate areaSelected: dragAreaBounds];
}
[self initialize];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[self initialize];
[self.dragArea removeFromSuperview];
self.dragArea = nil;
}
#pragma mark -
- (void) dealloc {
[dragArea release];
[super dealloc];
}
@end
然后,我有实现上述(MapViewController.h)中定义的协议的类:
#import "OverlaySelectionView.h"
typedef struct {
CLLocationDegrees minLatitude;
CLLocationDegrees maxLatitude;
CLLocationDegrees minLongitude;
CLLocationDegrees maxLongitude;
} LocationBounds;
@interface MapViewController : UIViewController<MKMapViewDelegate, OverlaySelectionViewDelegate> {
LocationBounds searchBounds;
UIBarButtonItem* areaButton;
而在我MapViewController.m,该areaSelected
方法是我进行触摸的坐标转换与地理坐标convertPoint:toCoordinateFromView:
#pragma mark - OverlaySelectionViewDelegate
- (void) areaSelected: (CGRect)screenArea
{
self.areaButton.style = UIBarButtonItemStyleBordered;
self.areaButton.title = @"Area";
CGPoint point = screenArea.origin;
// we must account for upper nav bar height!
point.y -= 44;
CLLocationCoordinate2D upperLeft = [mapView convertPoint: point toCoordinateFromView: mapView];
point.x += screenArea.size.width;
CLLocationCoordinate2D upperRight = [mapView convertPoint: point toCoordinateFromView: mapView];
point.x -= screenArea.size.width;
point.y += screenArea.size.height;
CLLocationCoordinate2D lowerLeft = [mapView convertPoint: point toCoordinateFromView: mapView];
point.x += screenArea.size.width;
CLLocationCoordinate2D lowerRight = [mapView convertPoint: point toCoordinateFromView: mapView];
searchBounds.minLatitude = MIN(lowerLeft.latitude, lowerRight.latitude);
searchBounds.minLongitude = MIN(upperLeft.longitude, lowerLeft.longitude);
searchBounds.maxLatitude = MAX(upperLeft.latitude, upperRight.latitude);
searchBounds.maxLongitude = MAX(upperRight.longitude, lowerRight.longitude);
// TODO: comment out to keep search rectangle on screen
[[self.view.subviews lastObject] removeFromSuperview];
[self performSelectorInBackground: @selector(lookupHistoryByArea) withObject: nil];
}
// this action is triggered when user selects the Area button to start selecting area
// TODO: connect this to areaButton yourself (I did it in Interface Builder)
- (IBAction) selectArea: (id) sender
{
PoliteAlertView* message = [[PoliteAlertView alloc] initWithTitle: @"Information"
message: @"Select an area to search by dragging your finger across the map"
delegate: self
keyName: @"swipe_msg_read"
cancelButtonTitle: @"Ok"
otherButtonTitles: nil];
[message show];
[message release];
OverlaySelectionView* overlay = [[OverlaySelectionView alloc] initWithFrame: self.view.frame];
overlay.delegate = self;
[self.view addSubview: overlay];
[overlay release];
self.areaButton.style = UIBarButtonItemStyleDone;
self.areaButton.title = @"Swipe";
}
你会发现,我MapViewController
有一个属性, areaButton
。 这是我的工具栏,通常所说区上的按钮。 在用户按下它之后,他们在区域选择模式,此时,按钮标签将更说刷卡提醒他们刷卡(也许不是最好的UI,但是这就是我)。
还要注意,当用户按下区进入区域选择模式,我告诉他们,告诉他们,他们需要刷卡警报。 因为这可能只是他们需要看到一次的提醒,我用我自己的PoliteAlertView ,这是一个自定义UIAlertView
,用户可以抑制(不再显示警报)。
我lookupHistoryByArea
仅仅是搜索我的位置的数据库,通过保存的方法searchBounds
(背景),然后在地图找到的位置上绘制新的叠加。 这显然会为您的应用程序不同。
限制
由于这是让用户选择近似的地方,我没有考虑地理精度是至关重要的。 这听起来并不像它应该是在你的应用程序,无论是。 因此,我刚刚绘制矩形以90度角,不占地球曲率等,对于只有几英里的地方,这应该是罚款。
我不得不做出有关短语基于触摸的绘图一些假设。 我决定,无论是最简单的方法来实现应用程序,最简单的触摸屏用户使用,是简单地确定一个单一的刷卡区。 绘制与触摸矩形将需要4个刷卡,而不是一个,引进非闭合矩形的复杂性,产量马虎的形状,而且可能得不到什么,他们甚至想用户。 所以,我试图保持用户界面简单。 如果你真的希望用户在地图上绘制 , 看到这个相关的答案,这是否 。
此应用ARC之前写的,而不是改变ARC。
在我的应用程序,实际上我使用互斥锁的主(UI)线程访问一些变量, 并在后台(搜索)线程。 我把代码出了这个例子。 根据您的数据库搜索的工作原理,以及如何选择运行搜索(GCD等),你应该确保审核自己的线程安全。
这是我的路怎么我的触摸转换为CLLocation
上MKMapView
。
它的工作原理与谷歌地图和苹果地图 ,以及:
- (void)viewDidLoad {
// ...
// ... where the _customMapView is a MKMapView object;
// find the gesture recogniser of the map
UIGestureRecognizer *_factoryDoubleTapGesture = nil;
NSArray *_gestureRecognizersArray = [_customMapView gestureRecognizers];
for (UIGestureRecognizer *_tempRecogniser in _gestureRecognizersArray) {
if ([_tempRecogniser isKindOfClass:[UITapGestureRecognizer class]]) {
if ([(UITapGestureRecognizer *)_tempRecogniser numberOfTapsRequired] == 2) {
_factoryDoubleTapGesture = _tempRecogniser;
break;
}
}
}
// my tap gesture recogniser
UITapGestureRecognizer *_locationTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(mapLocationTouchedUpInside:)];
if (_factoryDoubleTapGesture) [_locationTapGesture requireGestureRecognizerToFail:_factoryDoubleTapGesture];
[_customMapView addGestureRecognizer:_locationTapGesture];
// ...
}
和...
- (void)mapLocationTouchedUpInside:(UITapGestureRecognizer *)sender {
CGPoint _tapPoint = [sender locationInView:_customMapView];
CLLocationCoordinate2D _coordinates = [_customMapView convertPoint:_tapPoint toCoordinateFromView:_customMapView];
// ... do whatever you'd like with the coordinates
}
ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
ViewController.m
#import "ViewController.h"
#import <MapKit/MapKit.h>
@interface ViewController () <MKMapViewDelegate>
@property (weak, nonatomic) IBOutlet MKMapView *mapView;
@property (nonatomic, weak) MKPolyline *polyLine;
@property (nonatomic, strong) NSMutableArray *coordinates;
@property (weak, nonatomic) IBOutlet UIButton *drawPolygonButton;
@property (nonatomic) BOOL isDrawingPolygon;
@end
@implementation ViewController
@synthesize coordinates = _coordinates;
- (NSMutableArray*)coordinates
{
if(_coordinates == nil) _coordinates = [[NSMutableArray alloc] init];
return _coordinates;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (IBAction)didTouchUpInsideDrawButton:(UIButton*)sender
{
if(self.isDrawingPolygon == NO) {
self.isDrawingPolygon = YES;
[self.drawPolygonButton setTitle:@"done" forState:UIControlStateNormal];
[self.coordinates removeAllObjects];
self.mapView.userInteractionEnabled = NO;
} else {
NSInteger numberOfPoints = [self.coordinates count];
if (numberOfPoints > 2)
{
CLLocationCoordinate2D points[numberOfPoints];
for (NSInteger i = 0; i < numberOfPoints; i++)
points[i] = [self.coordinates[i] MKCoordinateValue];
[self.mapView addOverlay:[MKPolygon polygonWithCoordinates:points count:numberOfPoints]];
}
if (self.polyLine)
[self.mapView removeOverlay:self.polyLine];
self.isDrawingPolygon = NO;
[self.drawPolygonButton setTitle:@"draw" forState:UIControlStateNormal];
self.mapView.userInteractionEnabled = YES;
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if (self.isDrawingPolygon == NO)
return;
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self.mapView];
CLLocationCoordinate2D coordinate = [self.mapView convertPoint:location toCoordinateFromView:self.mapView];
[self addCoordinate:coordinate];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if (self.isDrawingPolygon == NO)
return;
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self.mapView];
CLLocationCoordinate2D coordinate = [self.mapView convertPoint:location toCoordinateFromView:self.mapView];
[self addCoordinate:coordinate];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (self.isDrawingPolygon == NO)
return;
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self.mapView];
CLLocationCoordinate2D coordinate = [self.mapView convertPoint:location toCoordinateFromView:self.mapView];
[self addCoordinate:coordinate];
[self didTouchUpInsideDrawButton:nil];
}
- (void)addCoordinate:(CLLocationCoordinate2D)coordinate
{
[self.coordinates addObject:[NSValue valueWithMKCoordinate:coordinate]];
NSInteger numberOfPoints = [self.coordinates count];
if (numberOfPoints > 2) {
MKPolyline *oldPolyLine = self.polyLine;
CLLocationCoordinate2D points[numberOfPoints];
for (NSInteger i = 0; i < numberOfPoints; i++) {
points[i] = [self.coordinates[i] MKCoordinateValue];
}
MKPolyline *newPolyLine = [MKPolyline polylineWithCoordinates:points count:numberOfPoints];
[self.mapView addOverlay:newPolyLine];
self.polyLine = newPolyLine;
if (oldPolyLine) {
[self.mapView removeOverlay:oldPolyLine];
}
}
}
#pragma mark - MKMapViewDelegate
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
MKOverlayPathView *overlayPathView;
if ([overlay isKindOfClass:[MKPolygon class]])
{
overlayPathView = [[MKPolygonView alloc] initWithPolygon:(MKPolygon*)overlay];
overlayPathView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
overlayPathView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
overlayPathView.lineWidth = 3;
return overlayPathView;
}
else if ([overlay isKindOfClass:[MKPolyline class]])
{
overlayPathView = [[MKPolylineView alloc] initWithPolyline:(MKPolyline *)overlay];
overlayPathView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
overlayPathView.lineWidth = 3;
return overlayPathView;
}
return nil;
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString * const annotationIdentifier = @"CustomAnnotation";
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier];
if (annotationView)
{
annotationView.annotation = annotation;
}
else
{
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationIdentifier];
annotationView.image = [UIImage imageNamed:@"annotation.png"];
annotationView.alpha = 0.5;
}
annotationView.canShowCallout = NO;
return annotationView;
}
@end
或者你可以在这里找到整个项目: https://github.com/tazihosniomar/MapKitDrawing
我希望它会帮助你。
尝试MKOverlayPathView。 在按图纸上的MKMapView的路径表示一个区域的问题是,除非你知道缩放比例,你不知道多少。 所以,你必须跟踪。