我需要创建一个简单的绘图应用程序。这个应用程序包含一个带有两个锚点的线,每端一个。用户应该能够触及锚点并拖动它来操纵线的长度和斜率。此外,用户应该能够触及连接两个锚点的线,以移动它和屏幕周围的锚点。
我有点难过,我知道我可以通过简单地使用触地向上/向上来操纵长度和坡度,但我认为这不适用于多条线路?!任何人都能指出我应该看的方向吗?非常感谢:))
答案 0 :(得分:1)
编辑:我重写了答案,这一次是通过实施一个简短的测试。下面的源代码执行以下操作:在触摸下,它检查列表self.lineDrawView.lines
内的每个点到当前触摸点的距离。如果距离低于10像素,则保存当前触摸点及其列表索引。
如果没有找到匹配点,则另一个函数遍历由self.lineDrawView.lines
内的对组成的所有行,并计算到每一行的距离(到行代码的距离here)。同样,如果距离低于10 px,则保存当前触摸点以及当前行的起点和终点。
然后,在触摸移动时,移动保存的点或通过上一个降落点与当前触摸位置之间的距离重新计算保存的行。
视图控制器的标题:
#import <UIKit/UIKit.h>
#import "myView.h"
@interface ViewController : UIViewController
{
CGPoint dragStartingPoint, lineOriginStart, lineOriginEnd;
int currentPointIndex, currentLineIndex;
}
@property (retain) myView *lineDrawView;
@property (retain) UITouch *currentTouch;
@end
视图控制器的来源:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.lineDrawView = [[myView alloc] initWithFrame:self.view.frame];
[self.view addSubview:self.lineDrawView];
self.lineDrawView.lines = [[NSMutableArray alloc] init];
[self.lineDrawView.lines addObject:[NSValue valueWithCGPoint:CGPointMake( 10, 10)]];
[self.lineDrawView.lines addObject:[NSValue valueWithCGPoint:CGPointMake(300, 100)]];
[self.lineDrawView.lines addObject:[NSValue valueWithCGPoint:CGPointMake(200, 400)]];
[self.lineDrawView.lines addObject:[NSValue valueWithCGPoint:CGPointMake( 50, 300)]];
}
-(float)distanceOfPoint:(CGPoint)p toLineWith:(CGPoint)v0 and:(CGPoint)v1
{
float vx = v0.x - p.x;
float vy = v0.y - p.y;
float ux = v1.x - v0.x;
float uy = v1.y - v0.y;
float length = ux * ux + uy * uy;
float result;
float det = (-vx * ux) + (-vy * uy);
// if this is < 0 or > length then it's outside the line segment
if(det < 0)
result = (v0.x - p.x) * (v0.x - p.x) + (v0.y - p.y) * (v0.y - p.y);
else if(det > length)
result = (v1.x - p.x) * (v1.x - p.x) + (v1.y - p.y) * (v1.y - p.y);
else
{
det = ux * vy - uy * vx;
result = (det * det) / length;
}
return sqrtf(result);
}
-(int)getLineNearToPoint:(CGPoint)p withMaximumDistance:(float)d
{
CGPoint p1, p2;
NSValue *v1, *v2;
for(int i=0; i<self.lineDrawView.lines.count/2; i++)
{
v1 = [self.lineDrawView.lines objectAtIndex:i*2+0];
v2 = [self.lineDrawView.lines objectAtIndex:i*2+1];
p1 = [v1 CGPointValue];
p2 = [v2 CGPointValue];
if([self distanceOfPoint:p toLineWith:p1 and:p2]<=d) return i;
}
return -1;
}
-(int)getPointNearToPoint:(CGPoint)p withinRadius:(float)r
{
float dx, dy;
CGPoint p2;
NSValue *v;
for(int i=0; i<self.lineDrawView.lines.count; i++)
{
v = [self.lineDrawView.lines objectAtIndex:i];
p2 = [v CGPointValue];
dx = p.x - p2.x;
dy = p.y - p2.y;
if(sqrtf(dx*dx + dy*dy)<=r) return i;
}
return -1;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
int iPoint, iLine;
currentLineIndex = -1;
currentPointIndex = -1;
for(UITouch *t in touches)
{
// check if a starting/ending point is near the current touch
CGPoint p = [t locationInView:self.view];
iPoint = [self getPointNearToPoint:p withinRadius:10];
if(iPoint != -1)
{
currentPointIndex = iPoint;
self.currentTouch = t;
}
// check if current touch is near a line
iLine = [self getLineNearToPoint:p withMaximumDistance:10];
if((iLine != -1) && (iPoint == -1))
{
currentLineIndex = iLine;
self.currentTouch = t;
// save current touch position
dragStartingPoint = p;
// save original starting/ending point
NSValue *v1 = [self.lineDrawView.lines objectAtIndex:iLine*2+0];
NSValue *v2 = [self.lineDrawView.lines objectAtIndex:iLine*2+1];
lineOriginStart = [v1 CGPointValue];
lineOriginEnd = [v2 CGPointValue];
}
// only use first touch, discard the rest
break;
}
[self.lineDrawView setNeedsDisplay];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for(UITouch *t in touches)
{
// only respond to touch move events of the touch previously assigned
// to a point or line
if(t != self.currentTouch) continue;
CGPoint p = [t locationInView:self.view];
// Are we moving a starting/ending point?
if(currentPointIndex != -1)
{
NSValue *v = [NSValue valueWithCGPoint:p];
[self.lineDrawView.lines replaceObjectAtIndex:currentPointIndex withObject:v];
}
// Are we moving a line?
if(currentLineIndex != -1)
{
// calculate drag distance
float dx = p.x - dragStartingPoint.x;
float dy = p.y - dragStartingPoint.y;
// calculate new starting/ending points
CGPoint p1 = CGPointMake(lineOriginStart.x+dx, lineOriginStart.y+dy);
CGPoint p2 = CGPointMake(lineOriginEnd.x+dx, lineOriginEnd.y+dy);
NSValue *v1 = [NSValue valueWithCGPoint:p1];
NSValue *v2 = [NSValue valueWithCGPoint:p2];
// replace old values
[self.lineDrawView.lines replaceObjectAtIndex:currentLineIndex*2+0 withObject:v1];
[self.lineDrawView.lines replaceObjectAtIndex:currentLineIndex*2+1 withObject:v2];
}
// only use first touch, discard the rest
break;
}
[self.lineDrawView setNeedsDisplay];
}
- (void)dealloc
{
self.lineDrawView.lines = nil;
[super dealloc];
}
@end
绘图的标题:
#import <UIKit/UIKit.h>
@interface myView : UIView
@property (retain) NSMutableArray *lines;
@end
绘画来源:
#import "myView.h"
@implementation myView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self) {
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
// fill background
CGContextSetRGBFillColor(context, 0.5, 0.5, 0.5, 1.0);
CGContextFillRect(context, self.frame);
// draw lines
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextSetLineWidth(context, 2.0);
for(int i=0; i<self.lines.count/2; i++)
{
CGPoint p1 = [[self.lines objectAtIndex:i*2+0] CGPointValue];
CGPoint p2 = [[self.lines objectAtIndex:i*2+1] CGPointValue];
CGContextMoveToPoint(context, p1.x, p1.y);
CGContextAddLineToPoint(context, p2.x, p2.y);
}
CGContextStrokePath(context);
}
@end
答案 1 :(得分:1)
我一直在研究类似的问题,最后我使用类似于此链接的UIWebView
http://mbostock.github.com/protovis/ex/splines.html
我可以使用
获取积分列表[myWebview stringByEvaluatingJavaScriptFromString....]
我必须对JS代码进行一些更改,以处理触摸开始和触摸结束事件,而不是鼠标按下并鼠标移动以使其在iPad / iPhone上工作