在iOS上用手指绘制贝塞尔曲线?

8

嗨,我正在尝试根据用户输入在iOS中生成贝塞尔曲线。是否有现有的类可以实现此功能?有人能否给我一个大致的概要阐述所需的内容?我只需要帮助找到正确的起点。


2
在Mike Nachbaur的博客上有关于这个完整的介绍。你可以在这里找到文章,它主要是关于在用户绘制的贝塞尔曲线上对物体进行动画处理的。 - Neal L
以下是我在相关问题上的回答副本。我编写了一些函数,可以帮助您实现这一点。请阅读我的文章以获取更多信息。 代码位于我的github仓库中。在我的文章中,您还将找到一个视频,演示了这些函数的用法。 - Petrakeas
这就是你需要的。只需查看名为如何构建iOS简单绘画应用程序的教程即可。 - fyasar
这个链接非常有用。它使用UIBezierPath类通过手指触摸平滑地绘制直线和曲线。 - YogiAR
2个回答

10

如果你想保持Objective-C,你可以使用UIBezierPath的addCurveToPoint:controlPoint1:controlPoint2:方法。你也可以使用一个类似命名的函数与CGPaths一起使用。当使用贝塞尔曲线时,你需要4个点:起始点、终点和每个端点的控制点来定义曲线。

一种定义这个曲线的方法是让用户拖动手指来定义起点和终点,然后在屏幕上点击控制点。这里有一个处理此操作的示例视图。

BezierView.h

enum {
    BezierStateNone = 0,
    BezierStateDefiningLine,
    BezierStateDefiningCP1,
    BezierStateDefiningCP2
};
@interface BezierView : UIView {
    CGPoint startPt, endPt, cPt1, cPt2;
    UInt8 state;
    UIBezierPath *curvePath;
  @private
    UITouch *currentTouch;
}
@property (nonatomic, retain) UIBezierPath *curvePath;
@end

BezierView.m

@interface BezierView
@dynamic curvePath;
- (UIBezierPath *)curvePath {
    return [[curvePath retain] autorelease];
}
- (void)setCurvePath:(UIBezierPath *)newPath {
    id tmp = curvePath;
    curvePath = [newPath retain];
    [tmp release];
    state = BezierStateNone;
    [self setNeedsDisplay];
}
- (void)_updateCurve {
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:startPt];
    [path addCurveToPoint:endPt controlPoint1:cPt1 controlPoint2:cPt2];
}
- (void)_calcDefaultControls {
    if(ABS(startPt.x - endPt.x) > ABS(startPt.y - endPt.y)) {
        cPt1 = (CGPoint){(startPt.x + endPt.x) / 2, startPt.y};
        cPt2 = (CGPoint){cPt1.x, endPt.y};
    } else {
        cPt1 = (CGPoint){startPt.x, (startPt.y + endPt.y) / 2};
        cPt2 = (CGPoint){endPt.x, cPt1.y};
    }
}
- (void)drawRect:(CGRect)rect {
    UIBezierPath *path = self.curvePath;
    if(path) [path stroke];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    if(currentTouch) return;
    if(state == BezierStateNone) {
        state = BezierStateDefiningLine;
        currentTouch = [touches anyObject];
        startPt = [currentTouch locationInView:self];
    } else if(state == BezierStateDefiningCP1) {
        currentTouch = [touches anyObject];
        cPt1 = [currentTouch locationInView:self];
        [self _updateCurve];
    } else if(state == BezierStateDefiningCP2) {
        currentTouch = [touches anyObject];
        cPt2 = [currentTouch locationInView:self];
        [self _updateCurve];
    }
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    if(!currentTouch) return;
    if(state == BezierStateDefiningLine) {
        endPt = [currentTouch locationInView:self];
        [self _calcDefaultControls];
        [self _updateCurve];
    } else if(state == BezierStateDefiningCP1) {
        cPt1 = [currentTouch locationInView:self];
        [self _updateCurve];
    } else if(state == BezierStateDefiningCP2) {
        cPt2 = [currentTouch locationInView:self];
        [self _updateCurve];
    }
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    if(!currentTouch) return;
    if(state == BezierStateDefiningLine) {
        state = BezierStateDefiningCP1;
    } else if(state == BezierStateDefiningCP1) {
        state = BezierStateDefiningCP2;
    } else if(state == BezierStateDefiningCP2) {
        state = BezierStateNone;
    }
    currentTouch = nil;
}
- (void)touchesCanceled:(NSSet *)touches withEvent:(UIEvent *)event {
    if(state == BezierStateDefiningLine) {
        self.curvePath = nil;
        self.state = BezierStateNone;
    }
    self.currentTouch = nil;
}

它什么也没画出来 :( - Coldsteel48

4
好的,最简单的方法可能是通过继承UIView并使用CoreGraphics进行绘制。请查看QuarzDemo中的示例代码。 为您的自定义视图类实现drawInRect方法,并使用touchesBegantouchesMoved等来检测用户的触摸事件。
以下是一个绘制贝塞尔曲线的示例代码(取自QuarzDemo):
// Drawing with a white stroke color
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
// Draw them with a 2.0 stroke width so they are a bit more visible.
CGContextSetLineWidth(context, 2.0);

// Draw a bezier curve with end points s,e and control points cp1,cp2
CGPoint s = CGPointMake(30.0, 120.0);
CGPoint e = CGPointMake(300.0, 120.0);
CGPoint cp1 = CGPointMake(120.0, 30.0);
CGPoint cp2 = CGPointMake(210.0, 210.0);
CGContextMoveToPoint(context, s.x, s.y);
CGContextAddCurveToPoint(context, cp1.x, cp1.y, cp2.x, cp2.y, e.x, e.y);
CGContextStrokePath(context);

希望这能帮助你入门IT技术;)

1
phix23:非常感谢您的帮助回复。如果我想要一个平滑插值曲线,我需要自己开发算法吗?我希望使用尽可能少的顶点生成曲线。 - Brendan
你好@phix23,请看一下这个链接https://dev59.com/a3rZa4cB1Zd3GeqP7dUj,给出你的专业建议。 - Ranjit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接