我正在尝试创建一个应用程序,用户每3次点击一次绘制角度。每次点击都会创建角度点并连接它们。
这很简单。然而,现在我正试图使这些角度可编辑,并且变得更加困难。当我完成我的3次点击并触及touchesEnded时,我将这三个点添加到一个名为segment的NSObject子类中,该子类有三个属性,firstPoint,secondPoint和thirdPoint,它精确地存储了它。
然后我将'segment'对象添加到数组中。每当touchesBegan被调用时,我都会进入我的数组的for循环。如果水龙头在“段”对象的3个CGPoint中的任何一个的25px范围内,那么我不会绘制新的角度,我会编辑该角度。
据我所知,在这一点上,感谢你们,没有任何问题或错误!我只是检查一般的改进/简化,保持我正在使用的当前方法。我希望我能把这笔钱给大家,因为你们都非常乐于助人!
这是我迄今为止最大的项目,我非常感谢一些见解。如果你想要它并且可以处理它,这是一个非常好的挑战。任何帮助都是 IMMENSELY 赞赏。如果您能想出更好的方法来处理我想要完成的事情,请务必告诉我们!
注意:要绘制,只需点击/点击屏幕即可。
以下是最相关的代码:
drawingsubclass.m
#import "SegmentDraw.h"
#import <QuartzCore/QuartzCore.h>
BOOL editing1 = FALSE;
BOOL editing2 = FALSE;
BOOL editing3 = FALSE;
BOOL erased = FALSE;
int radius = 35;
int handleSize = 20;
@implementation SegmentDraw {
UIImage *incrementalImage;
}
@synthesize first;
@synthesize second;
@synthesize third;
- (id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
[self setMultipleTouchEnabled:NO];
[self setBackgroundColor:[UIColor clearColor]];
first = CGPointZero;
second = CGPointZero;
third = CGPointZero;
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self];
for (Segment *currentSegment in self.tapArray) {
int xDistance = abs(point.x - currentSegment.firstPoint.x);
int yDistance = abs(point.y - currentSegment.firstPoint.y);
int firstDistance = sqrtf(xDistance * xDistance + yDistance * yDistance);
int xDistance2 = abs(point.x - currentSegment.secondPoint.x);
int yDistance2 = abs(point.y - currentSegment.secondPoint.y);
int secondDistance = sqrtf(xDistance2 * xDistance2 + yDistance2 * yDistance2);
int xDistance3 = abs(point.x - currentSegment.thirdPoint.x);
int yDistance3 = abs(point.y - currentSegment.thirdPoint.y);
int thirdDistance = sqrtf(xDistance3 * xDistance3 + yDistance3 * yDistance3);
if (firstDistance <= radius) {
NSLog(@"First point matches");
editing1 = TRUE;
editing2 = FALSE;
editing3 = FALSE;
first = point;
second = currentSegment.secondPoint;
third = currentSegment.thirdPoint;
self.segmentBeingEdited = currentSegment;
[self setNeedsDisplay];
[self drawBitmap];
erased = FALSE;
return;
}
else if (secondDistance <= radius) {
NSLog(@"Second point matches");
editing2 = TRUE;
editing1 = FALSE;
editing3 = FALSE;
first = currentSegment.firstPoint;
second = point;
third = currentSegment.thirdPoint;
self.segmentBeingEdited = currentSegment;
[self setNeedsDisplay];
[self drawBitmap];
erased = FALSE;
return;
}
else if (thirdDistance <= radius) {
NSLog(@"Third point matches");
editing3 = TRUE;
editing1 = FALSE;
editing2 = FALSE;
first = currentSegment.firstPoint;
second = currentSegment.secondPoint;
third = point;
self.segmentBeingEdited = currentSegment;
[self setNeedsDisplay];
[self drawBitmap];
erased = FALSE;
return;
}
else {
editing1 = FALSE;
editing2 = FALSE;
editing3 = FALSE;
}
}
if (CGPointEqualToPoint(first, CGPointZero)) {
first = [touch locationInView:self];
}
else if (!CGPointEqualToPoint(first, CGPointZero) && CGPointEqualToPoint(second, CGPointZero)) {
second = [touch locationInView:self];
}
else if (!CGPointEqualToPoint(first, CGPointZero) && !(CGPointEqualToPoint(second, CGPointZero)) && CGPointEqualToPoint(third, CGPointZero)) {
third = [touch locationInView:self];
}
else {
//[self drawBitmap];
first = [touch locationInView:self];
second = CGPointZero;
third = CGPointZero;
}
[self setNeedsDisplay];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self];
for (Segment *currentSegment in self.tapArray) {
if (editing1) {
editing2 = FALSE;
editing3 = FALSE;
first = point;
second = self.segmentBeingEdited.secondPoint;
third = self.segmentBeingEdited.thirdPoint;
//self.segmentBeingEdited = currentSegment;
if (erased == FALSE) {
[self drawBitmap];
// NSLog(@"YOU NEED TO ERASE.");
}
[self setNeedsDisplay];
return;
}
else if (editing2) {
editing1 = FALSE;
editing3 = FALSE;
first = self.segmentBeingEdited.firstPoint;
second = point;
third = self.segmentBeingEdited.thirdPoint;
//self.segmentBeingEdited = currentSegment;
if (erased == FALSE) {
[self drawBitmap];
// NSLog(@"YOU NEED TO ERASE.");
}
[self setNeedsDisplay];
return;
}
else if (editing3) {
// NSLog(@"It's editing time, yo");
editing1 = FALSE;
editing2 = FALSE;
first = self.segmentBeingEdited.firstPoint;
second = self.segmentBeingEdited.secondPoint;
third = point;
//self.segmentBeingEdited = currentSegment;
if (erased == FALSE) {
[self drawBitmap];
// NSLog(@"YOU NEED TO ERASE.");
}
[self setNeedsDisplay];
return;
}
else {
editing1 = FALSE;
editing2 = FALSE;
editing3 = FALSE;
}
}
if (!CGPointEqualToPoint(first, CGPointZero) && CGPointEqualToPoint(second, CGPointZero)) {
first = [touch locationInView:self];
}
else if (!CGPointEqualToPoint(first, CGPointZero) && !(CGPointEqualToPoint(second, CGPointZero)) && CGPointEqualToPoint(third, CGPointZero)) {
second = [touch locationInView:self];
}
else if (!CGPointEqualToPoint(first, CGPointZero) && !(CGPointEqualToPoint(second, CGPointZero)) && !(CGPointEqualToPoint(third, CGPointZero))) {
third = [touch locationInView:self];
}
else {
first = [touch locationInView:self];
second = CGPointZero;
third = CGPointZero;
}
[self setNeedsDisplay];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSUInteger index;
if (editing1 || editing2 || editing3) {
index = [self.tapArray indexOfObject:self.segmentBeingEdited];
Segment *datSegment = [self.tapArray objectAtIndex:index];
datSegment.firstPoint = first;
datSegment.secondPoint = second;
datSegment.thirdPoint = third;
}
if (!CGPointEqualToPoint(third, CGPointZero) && editing1 == FALSE && editing2 == FALSE && editing3 == FALSE) {
Segment *segment = [[Segment alloc] init];
segment.firstPoint = first;
segment.secondPoint = second;
segment.thirdPoint = third;
if (self.tapArray == nil) {
self.tapArray = [[NSMutableArray alloc] init];
}
[self.tapArray addObject:segment];
}
editing1 = FALSE;
editing2 = FALSE;
editing3 = FALSE;
erased = FALSE;
[self drawBitmap];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
}
- (void)drawRect:(CGRect)rect {
[incrementalImage drawInRect:rect];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextSetLineWidth(context, 5.0);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineJoin(context, kCGLineJoinRound);
if (!CGPointEqualToPoint(first, CGPointZero)) {
CGRect rectangle = CGRectMake(first.x - 10, first.y - 10, handleSize, handleSize);
CGContextAddEllipseInRect(context, rectangle);
CGContextMoveToPoint(context, first.x, first.y);
if (!CGPointEqualToPoint(second, CGPointZero)) {
CGContextAddLineToPoint(context, second.x, second.y);
CGRect rectangle2 = CGRectMake(second.x - 10, second.y - 10, handleSize, handleSize);
CGContextAddEllipseInRect(context, rectangle2);
CGContextMoveToPoint(context, second.x, second.y);
}
if (!CGPointEqualToPoint(third, CGPointZero)) {
CGContextAddLineToPoint(context, third.x, third.y);
CGRect rectangle3 = CGRectMake(third.x - 10, third.y - 10, handleSize, handleSize);
CGContextAddEllipseInRect(context, rectangle3);
}
CGContextStrokePath(context);
}
}
- (void)drawBitmap {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0);
if (!incrementalImage) { // first draw;
UIBezierPath *rectpath = [UIBezierPath bezierPathWithRect:self.bounds]; // enclosing bitmap by a rectangle defined by another UIBezierPath object
[[UIColor clearColor] setFill];
[rectpath fill]; // fill it
}
[incrementalImage drawAtPoint:CGPointZero];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextSetLineWidth(context, 5.0);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineJoin(context, kCGLineJoinRound);
if (editing1 || editing2 || editing3) {
// CGContextBeginTransparencyLayer(context, NULL);
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextSetLineWidth(context, 6.0);
//CGContextSetBlendMode(context, kCGBlendModeColor);
if (!CGPointEqualToPoint(self.segmentBeingEdited.firstPoint, CGPointZero)) {
CGContextMoveToPoint(context, self.segmentBeingEdited.firstPoint.x, self.segmentBeingEdited.firstPoint.y);
if (!CGPointEqualToPoint(self.segmentBeingEdited.secondPoint, CGPointZero)) {
CGContextAddLineToPoint(context, self.segmentBeingEdited.secondPoint.x, self.segmentBeingEdited.secondPoint.y);
}
if (!CGPointEqualToPoint(self.segmentBeingEdited.thirdPoint, CGPointZero)) {
CGContextAddLineToPoint(context, self.segmentBeingEdited.thirdPoint.x, self.segmentBeingEdited.thirdPoint.y);
}
CGContextStrokePath(context);
// CGContextEndTransparencyLayer(context);
}
incrementalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
erased = TRUE;
return;
}
CGContextSetBlendMode(context, kCGBlendModeNormal);
if (!CGPointEqualToPoint(first, CGPointZero)) {
CGContextMoveToPoint(context, first.x, first.y);
if (!CGPointEqualToPoint(second, CGPointZero)) {
CGContextAddLineToPoint(context, second.x, second.y);
}
if (!CGPointEqualToPoint(third, CGPointZero)) {
CGContextAddLineToPoint(context, third.x, third.y);
}
CGContextStrokePath(context);
}
incrementalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
@end
回顾一下,我想绘制一堆角度,然后能够通过点击我想要编辑的角度的3个点中的任何一个来编辑它们中的任何一个。然后通过拖动,编辑角度以扩展到水龙头当前所在的位置。只是想让它变得更好/更简单。任何评论/见解欢迎!
答案 0 :(得分:2)
好的 - 这可能不是您想要的......我创建了一个可编辑的角度UI,我认为这是一个很好的方式来组合您想要做的事情。 (我喜欢这样的项目)
有一个画布,视图控制器,角度视图和角度视图视图。记录画布上的点击。当3次点击发生时,会创建一个角度视图(其中有手柄)。点击现有角度选择它(显示句柄和选择UI)
该项目位于github。
修改强>
我没有使用手势识别器,但这可能是一个不错的选择。
答案 1 :(得分:1)
您没有正确处理编辑标记。你打电话给touchesBegan:
if(yDistance2 <= 25 || editing){
NSLog(@"It's editing time, yo");
editing = TRUE; // Here's your problem
这意味着touchesMoved
,当你点击:
if(xDistance <= 25 || editing) // Note the "Or editing"
editing
等于true,这意味着它将移动第1点,因为它首先命中if语句,无论哪个点设置为。
<强>结论强>
您需要为每个点使用特定的编辑标志。不是共享的。至少没有进行or
检查。或者更好的是,处理touchesMoved
更好一点。您无需从touchesBegan
虽然与您的问题没有完全相关,但我相信您也在if语句中交换point2和point3。检查xDistance2:
else if(xDistance2 <= 25 || editing){
NSLog(@"X is pretty close");
if(yDistance2 <= 25 || editing){
NSLog(@"It's editing time, yo");
editing = TRUE;
first = currentSegment.firstPoint;
second = currentSegment.secondPoint;
third = point; // <- Why are you setting third to point and not second to point.
self.segmentBeingEdited = currentSegment;
[self setNeedsDisplay];
return;
}
}
检查XDistance3时同样如此。你设置第二个点而不是第三个。
答案 2 :(得分:1)
你的代码中有一个明显的和一个非显而易见的错误。
显而易见的一点是,在您的touchesBegan
方法中,您错误地设置了second
和third
的值 - 当您接近第二点时,您正在分配触摸将值指向third
变量,反之亦然。
不明显的一个是你有一个全局变量editing
,它在touchesBegan
中设置为你正在编辑的任何一个点,然后在or
条件下使用touchesMoved
,意思是只要你拖动任何东西,它就会立即落到数组中第一个项目的第一个点。
你的touchesMoved
方法已经太多了。您应该在touchesBegan
中确定正在编辑哪个分段的哪个点,然后在touchesMoved
中仅在编辑特定点时执行任何操作 - 不要尝试再次计算出您正在编辑的内容。您也不需要维护所有单独的状态 - 您有一个segmentBeingEdited
属性,只需使用它,并使用一个标志来说明您正在编辑哪个点,并在拖动时直接更新值
通过在日志消息中包含一些上下文,这几乎是显而易见的 - 复制粘贴相同的日志消息到处都会让您最终感到困惑。
以下是touchesXX
方法的改编版本。我删除了很多不必要的代码并为您说明。它仍然不能正常工作 - 绘制已编辑的段有问题。在某些时候,您需要添加代码以进行完全重绘,或者将每个图像分开并删除不需要的图像,但希望我正在解释的原则将是直截了当的。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
self.segmentBeingEdited = nil;
pointBeingEdited = 0;
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self];
// Are we editing an existing segment?
for(int i = 0;i<self.tapArray.count;i++){
Segment *currentSegment = [self.tapArray objectAtIndex:i];
int xDistance = abs(point.x - currentSegment.firstPoint.x);
int yDistance = abs(point.y - currentSegment.firstPoint.y);
int xDistance2 = abs(point.x - currentSegment.secondPoint.x);
int yDistance2 = abs(point.y - currentSegment.secondPoint.y);
int xDistance3 = abs(point.x - currentSegment.thirdPoint.x);
int yDistance3 = abs(point.y - currentSegment.thirdPoint.y);
if(xDistance <= 25){
if(yDistance <= 25){
pointBeingEdited = 1;
}
}
else if(xDistance2 <= 25 ){
if(yDistance2 <= 25){
pointBeingEdited = 2;
}
}
else if(xDistance3 <= 25){
if(yDistance3 <= 25){
pointBeingEdited = 3;
}
}
if (pointBeingEdited != 0)
{
NSLog(@"editing point %d",pointBeingEdited);
self.segmentBeingEdited = currentSegment;
return;
}
}
// Creating a new segment. Update data.
if (pointBeingAdded == 0)
{
first = [touch locationInView:self];
second = CGPointZero;
third = CGPointZero;
}
else if (pointBeingAdded == 1)
{
second = [touch locationInView:self];
}
else if (pointBeingAdded == 2)
{
third = [touch locationInView:self];
}
pointBeingAdded++;
[self setNeedsDisplay];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if (!self.segmentBeingEdited)
return;
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self];
if (pointBeingEdited == 1)
{
self.segmentBeingEdited.firstPoint = point;
}
else if (pointBeingEdited == 2)
{
self.segmentBeingEdited.secondPoint = point;
}
else if (pointBeingEdited == 3)
{
self.segmentBeingEdited.thirdPoint = point;
}
[self drawBitmap];
[self setNeedsDisplay];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if(self.segmentBeingEdited){
first = CGPointZero;
second = CGPointZero;
third = CGPointZero;
}
if(pointBeingAdded == 3){
// Add new segment
Segment *segment = [[Segment alloc] init];
segment.firstPoint = first;
segment.secondPoint = second;
segment.thirdPoint = third;
if(self.tapArray == nil){
self.tapArray = [[NSMutableArray alloc] init];
}
[self.tapArray addObject:segment];
pointBeingAdded = 0;
}
[self drawBitmap];
self.segmentBeingEdited = nil;
}
答案 3 :(得分:1)
我想谈谈你代码的一些事情:
1-没有必要但是,您可以使用水龙头和平移手势识别器,我认为这会简化您的代码。
2-当你试图找到正在编辑的点时你重复了很多代码,你可以像这样迭代每个段的点:
- (void)tapAction:(UITapGestureRecognizer *)recognizer {
CGPoint point = [recognizer locationInView:self];
self.segmentBeingEdited = nil;
CGPoint currentPoint;
for (Segment *segment in self.tapArray) {
for (NSInteger p = 0; p < 3; p++) {
currentPoint = [segment pointAtIndex:p];
CGFloat distance = fDistance(point, currentPoint);
if (distance <= 25.0) {
self.segmentBeingEdited = segment;
self.pointBeingEdited = p;
[self setNeedsDisplay];
return;
}
}
}
Segment *segment = [self.tapArray lastObject];
if (!segment || segment.points == 3) {
segment = [[Segment alloc] init];
[self.tapArray addObject:segment];
}
[segment setPoint:point atIndex:segment.points];
segment.points = segment.points + 1;
[self setNeedsDisplay];
}
3- Segment
类可以根据索引0,1,2和已添加的点数来获取和设置点的方法,我认为这会增加内聚力并简化代码。 / p>
4-用于确定从水龙头位置到某个点的距离是否小于25的算法......好吧,它可以工作但技术上不正确,你应该使用这样的东西:
static inline CGFloat fDistance(CGPoint point1, CGPoint point2) {
CGFloat dx = point1.x - point2.x;
CGFloat dy = point1.y - point2.y;
return sqrtf(dx * dx + dy * dy); }
5-我注意到你在某些if中使用CGPointEqualToPoint(point, CGPointZero)
,再次,它有效,但有更好的方法,你可以用一个标志来找到下一个要添加的点。
最后,您可以使用平移手势识别器来编辑选定的点:
- (void)panAction:(UIPanGestureRecognizer *)recognizer {
CGPoint location = [recognizer locationInView:self];
switch (recognizer.state) {
case UIGestureRecognizerStateBegan:
{
CGPoint point = [self.segmentBeingEdited pointAtIndex:self.pointBeingEdited];
CGFloat distance = fDistance(location, point);
if (distance > 25.0) {
self.segmentBeingEdited = nil;
}
break;
}
case UIGestureRecognizerStateChanged:
{
if (self.segmentBeingEdited) {
[self.segmentBeingEdited setPoint:location atIndex:self.pointBeingEdited];
[self setNeedsDisplay];
}
}
default:
break;
}
}
我希望这可能有用。