gpt4 book ai didi

iOS + MKMapView 用户触摸绘图

转载 作者:IT王子 更新时间:2023-10-29 07:50:23 25 4
gpt4 key购买 nike

我已经为这个问题搜索了很多,但似乎没有一个能完全符合我的要求。很多教程向我展示了如何在代码中添加线条和多边形,但没有使用手绘图。

问题如下:

我正在构建一个房地产应用程序。如果用户在 MKMapView 上,它可以在他/她想买/租房子的特定区域周围绘制一个矩形/圆形/...。然后我需要在用户选择的区域内显示对应的结果。

目前,我在 MKMapView 之上有一个 UIView,我在其中进行了一些自定义绘图,有没有一种方法可以将点转换为坐标,或者..?或者这完全不是这样做的方式?我也听说过 MKMapOverlayView 等。但我不确定如何使用它。

谁能给我指出正确的方向,或者他有一些示例代码或教程可以帮助我完成我需要的东西吗?

谢谢

最佳答案

我有一个基本上可以执行此操作的应用程序。我有一个 map View ,屏幕顶部有一个工具栏。当您按下该工具栏上的按钮时,您现在处于可以在 map 上滑动手指的模式。滑动的开始和结束将代表矩形的角。该应用程序将绘制一个半透明的蓝色矩形叠加层以显示您选择的区域。当您抬起手指时,矩形选择完成,应用开始在我的数据库中搜索位置。

我不处理圆圈,但我认为您可以做类似的事情,其中​​有两种选择模式(矩形或圆形)。在圆形选择模式下,滑动起点和终点可以代表圆心和边缘(半径)。或者,直径线的两端。我会把那部分留给你。

实现

首先,我定义了一个处理选择的透明覆盖层 (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

然后我有一个实现上面定义的协议(protocol)的类 (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。这是我工具栏上的一个按钮,通常显示为 Area。用户按下后,他们处于区域选择模式,此时按钮标签变为滑动以提醒他们滑动(可能不是最好的 UI,但这就是我所拥有的)。

另请注意,当用户按下 Area 进入区域选择模式时,我会向他们显示一个警告,告诉他们需要滑动。因为这可能只是他们需要看一次的提醒,所以我使用了自己的 PoliteAlertView ,这是一个自定义的 UIAlertView,用户可以抑制(不再显示警报)。

我的 lookupHistoryByArea 只是一种通过保存的 searchBounds(在后台)在我的数据库中搜索位置的方法,然后在 map 上绘制新的叠加层找到的位置。对于您的应用,这显然会有所不同。

限制

  • 因为这是为了让用户选择近似区域,所以我认为地理精度不是很重要。它听起来也不应该在您的应用程序中。因此,我只画了 90 度角的矩形,不考虑地球曲率等。对于只有几英里的区域,这应该没问题。

  • 我不得不对您的短语touch based drawing 做出一些假设。我决定,实现该应用程序的最简单方法,也是触摸屏用户最容易使用的方法,就是通过一次滑动来简单地定义区域。 绘制带触摸的矩形需要 4 次滑动而不是一次,引入非封闭矩形的复杂性,产生草率的形状,并且可能无法让用户获得他们想要的东西。所以,我试图保持 UI 简单。如果你真的想让用户在 map 上绘图see this related answer which does that .

  • 此应用是在 ARC 之前编写的,未针对 ARC 进行更改。

  • 在我的应用程序中,我确实对在主 (UI) 线程、 后台(搜索)线程中访问的一些变量使用了互斥锁。我为这个例子取出了那个代码。根据您的数据库搜索的工作方式以及您选择运行搜索的方式(GCD 等),您应该确保审核自己的线程安全。

关于iOS + MKMapView 用户触摸绘图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14374240/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com