How can I create objects along a path/BezierCurve? In other words, how can I create several UIButtons along a given path, with a given interval along that same path?
Have you solved your problem yet? if no, see this if it could help
//if the interval is kown as float, suggesting it named padding
//then you can
for(i=0;i<numOfPaddings;i++){
//create a button
UIButton *aButton = [UIButton buttonWithType:UIButtonRoundRect/*I forgot how to spell,but it does not metter*/];
//Set your button's position base on padding
[aButton setFrame:CGRectMake(padding+padding*i,20,50,20)];
}
iOS doesn't have a public API that directly gives you points spaced along a path. But there is a roundabout way to do it. Suppose you want points along the path spaced a distance of X apart.
First, create a CGPathRef
containing your path. (You can construct a UIBezierPath
if you prefer and then gets its CGPath
property.)
Then, call CGPathCreateCopyByDashingPath
, using a dash pattern of { X, X }
. For example:
static CGFloat const kSpace = 10;
CGPathRef dashedPath = CGPathCreateCopyByDashingPath(path, NULL, 0,
(CGFloat const []){ kSpace, kSpace }, 2);
This returns a new path containing multiple subpaths. Each subpath is a length X segment of the original path, and is separated from its neighboring subpaths by a distance of X along the original path. Thus the endpoints of the subpaths are spaced along the original path at an interval of length X.
So, finally, enumerate the dashed path using CGPathApply
, picking the endpoints and creating buttons there. First, you'll want to wrap it in a function that takes a block:
static void applyBlockToPathElement(void *info, const CGPathElement *element) {
void (^block)(const CGPathElement *) = (__bridge void (^)(const CGPathElement *))(info);
block(element);
}
void MyCGPathApplyBlock(CGPathRef path, void (^block)(const CGPathElement *element)) {
CGPathApply(path, (__bridge void *)(block), applyBlockToPathElement);
}
Then you can apply a block that finds the each subpath endpoint and creates a button there. Assuming you have a method named createButtonAtPoint:
, something like this should work:
__block BOOL isInSubpath = NO;
__block CGPoint subpathStart = CGPointZero;
__block CGPoint currentPoint = CGPointZero;
MyCGPathApplyBlock(dashedPath, ^(const CGPathElement *element) {
switch (element->type) {
case kCGPathElementMoveToPoint:
if (isInSubpath) {
[self createButtonAtPoint:currentPoint];
isInSubpath = NO;
}
currentPoint = element->points[0];
break;
case kCGPathElementCloseSubpath:
// This should not appear in a dashed path.
break;
case kCGPathElementAddLineToPoint:
case kCGPathElementAddQuadCurveToPoint:
case kCGPathElementAddCurveToPoint:
if (!isInSubpath) {
[self createButtonAtPoint:currentPoint];
isInSubpath = YES;
}
int pointIndex =
element->type == kCGPathElementAddLineToPoint ? 0
: element->type == kCGPathElementAddQuadCurveToPoint ? 1
: /* element->type == kCGPathElementAddCurveToPoint ? */ 2;
currentPoint = element->points[pointIndex];
break;
}
});