iOS-OC-Bézier Path简介

添加线条和多边形

  • Bézier的线和多边形是使用moveToPoint:addLineToPoint:方法逐点构建的简单形状。moveToPoint:方法设置你想要创建的形状的起点。从这一点开始,使用addLineToPoint:方法创建形状的线条。您可以连续创建这些线,每条线都是在上一个点和您指定的新点之间形成的。
- (void)drawRect:(CGRect)rect {
    UIBezierPath *bezierPath = [UIBezierPath bezierPath];
    [bezierPath moveToPoint:CGPointMake(100, 0)];
    [bezierPath addLineToPoint:CGPointMake(200, 0)];
    [bezierPath addLineToPoint:CGPointMake(300, 100)];
    [bezierPath addLineToPoint:CGPointMake(150, 200)];
    [bezierPath addLineToPoint:CGPointMake(0, 100)];
    [bezierPath closePath];
}

iOS-OC-Bézier Path简介_第1张图片

  • 对应点ABCDE,使用closePath,形成闭合图形。

    ** path的图是向上的,实际展示是向下翻转的。
    iOS-OC-Bézier Path简介_第2张图片

添加弧线

  • UIBezierPath类提供了使用弧段初始化新路径对象的支持。bezierPathWithArcCenter:radius:startAngle:endAngle:顺时针:方法的参数定义了包含所需圆弧的圆以及圆弧本身的起点和终点。
#define   DEGREES_TO_RADIANS(degrees)  ((pi * degrees)/ 180)
- (UIBezierPath *)createArcPath
{
   UIBezierPath *aPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(150, 150)
                           radius:75
                           startAngle:0
                           endAngle:DEGREES_TO_RADIANS(135)
                           clockwise:YES];
   return aPath;
}
//弧是顺时针方向形成的。(逆时针方向画圆弧的虚线部分)

iOS-OC-Bézier Path简介_第3张图片

添加曲线

  • UIBezierPath类支持在路径中添加Quadratic curveCubic curve Bézier。曲线段从当前点开始,到指定的点结束。曲线的形状使用起点和终点与一个或多个控制点之间的切线定义。添加曲线:

  • Quadratic curve :addQuadCurveToPoint:controlPoint:

  • Cubic curve :addCurveToPoint:controlPoint1:controlPoint2:

  • 因为曲线依赖于路径的当前点,所以必须在调用上述方法之前设置当前点。完成曲线后,当前点将更新为您指定的新终点。
    iOS-OC-Bézier Path简介_第4张图片

创建椭圆和矩形路径

椭圆和矩形是使用曲线和线段组合构建的常见路径类型。UIBezierPath类包括bezierPathWithRect:bezierPathWithOvalInRect:用于创建椭圆形或矩形路径的方便方法。这两个方法都创建一个新的路径对象,并用指定的形状初始化它。您可以立即使用返回的path对象,也可以根据需要向其添加更多形状。

如果你想添加一个矩形到一个现有的路径对象中,你必须使用moveToPoint:addLineToPoint:,和closePath方法,就像你对任何其他多边形一样。在矩形的最后一侧使用closePath方法可以方便地添加路径的最后一行,并标记矩形子路径的结束。

如果你想添加一个椭圆到一个现有的路径,最简单的方法是使用核心图形。虽然您可以使用addQuadCurveToPoint:controlPoint:来近似椭圆曲面,但CGPathAddEllipseInRect函数使用起来更简单,也更准确。有关详细信息,请参见核心图形函数修改路径

使用核心图形函数修改路径

  • UIBezierPath类实际上只是CGPathRef数据类型和与该路径相关的绘图属性的包装器。虽然您通常使用UIBezierPath类的方法添加直线段和曲线段,但该类还公开了一个CGPath属性,您可以使用该属性直接修改底层路径数据类型。当您希望使用核心图形框架的功能构建路径时,可以使用此属性。

  • 有两种方法来修改与UIBezierPath对象相关的路径。你可以完全使用Core Graphics函数来修改路径,或者你可以混合使用Core Graphics函数和UIBezierPath方法。在某些方面,完全使用Core Graphics调用修改路径更容易。您可以创建一个可变的CGPathRef数据类型,并调用您需要修改其路径信息的任何函数。完成后,将path对象分配给相应的UIBezierPath对象.

// Create the path data.
CGMutablePathRef cgPath = CGPathCreateMutable();
CGPathAddEllipseInRect(cgPath, NULL, CGRectMake(0, 0, 300, 300));
CGPathAddEllipseInRect(cgPath, NULL, CGRectMake(50, 50, 200, 200));
 
// Now create the UIBezierPath object.
UIBezierPath *aPath = [UIBezierPath bezierPath];
aPath.CGPath = cgPath;
aPath.usesEvenOddFillRule = YES;
 
// After assigning it to the UIBezierPath object, you can release
// your CGPathRef data type safely.
CGPathRelease(cgPath);
  • 如果你选择混合使用Core Graphics函数和UIBezierPath方法,你必须小心地在两者之间来回移动路径信息。因为UIBezierPath对象拥有其底层CGPathRef数据类型,所以不能简单地检索该类型并直接修改它。相反,您必须创建一个可变副本,修改副本,然后将副本赋值给CGPath属性.
UIBezierPath *aPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, 300, 300)];
 
// Get the CGPathRef and create a mutable version.
CGPathRef cgPath = aPath.CGPath;
CGMutablePathRef  mutablePath = CGPathCreateMutableCopy(cgPath);
 
// Modify the path and assign it back to the UIBezierPath object.
CGPathAddEllipseInRect(mutablePath, NULL, CGRectMake(50, 50, 200, 200));
aPath.CGPath = mutablePath;
 
// Release both the mutable copy of the path.
CGPathRelease(mutablePath);

渲染Bézier Path路径

  • 创建UIBezierPath对象后,你可以使用它的描边填充方法在当前图形上下文中渲染它。不过,在你调用这些方法之前,通常还有一些其他任务要执行,以确保你的路径被正确绘制:

      1. 使用UIColor类的方法设置所需的笔画填充颜色。
      1. 将形状放置在目标视图中您想要的位置。

      如果您创建了相对于点(0,0)的路径,则可以对当前绘图上下文应用适当的仿射转换。例如,要从点(10,10)开始绘制形状,您将调用CGContextTranslateCTM函数,并为水平和垂直平移值指定10。调整图形上下文(而不是路径对象中的点)是首选,因为通过保存和恢复以前的图形状态,可以更容易地撤消更改。

      1. 更新路径对象的绘图属性。UIBezierPath实例的绘图属性在呈现路径时覆盖与图形上下文相关的值。
- (void)drawRect:(CGRect)rect
{
    // Create an oval shape to draw.
    UIBezierPath *aPath = [UIBezierPath bezierPathWithOvalInRect:
                                CGRectMake(0, 0, 200, 100)];
 
    // Set the render colors.
    [[UIColor blackColor] setStroke];
    [[UIColor redColor] setFill];
 
    CGContextRef aRef = UIGraphicsGetCurrentContext();
 
    // If you have content to draw after the shape,
    // save the current state before changing the transform.
    //CGContextSaveGState(aRef);
 
    // Adjust the view's origin temporarily. The oval is
    // now drawn relative to the new origin point.
    CGContextTranslateCTM(aRef, 50, 50);
 
    // Adjust the drawing options as needed.
    aPath.lineWidth = 5;
 
    // Fill the path before stroking it so that the fill
    // color does not obscure the stroked line.
    [aPath fill];
    [aPath stroke];
 
    // Restore the graphics state before drawing any other content.
    //CGContextRestoreGState(aRef);
}

如上显示了一个drawRect:方法的示例实现,该方法在自定义视图中绘制一个椭圆形。椭圆边界矩形的左上角位于视图坐标系中的点(50,50)。因为填充操作直接绘制到路径边界,所以此方法在描边之前填充路径。这可以防止填充颜色遮住一半的描边线。
iOS-OC-Bézier Path简介_第5张图片

在路径上进行命中检测

  • 要确定一个触摸事件是否发生在路径的填充部分,你可以使用UIBezierPathcontainsPoint:方法。此方法针对路径对象中的所有封闭子路径测试指定点,如果它位于其中任何子路径上或其中任何子路径内,则返回YES

containsPoint:方法和Core Graphics命中测试函数仅在封闭路径上操作。对于打开的子路径,这些方法总是返回NO。如果要对打开的子路径进行命中检测,必须创建路径对象的副本,并在测试点之前关闭打开的子路径。

  • 如果你想在路径的描边部分(而不是填充区域)进行命中测试,你必须使用Core GraphicsCGContextPathContainsPoint函数允许您测试当前分配给图形上下文的路径的填充部分或描边部分上的点。
- (BOOL)containsPoint:(CGPoint)point onPath:(UIBezierPath *)path inFillArea:(BOOL)inFill
{
   CGContextRef context = UIGraphicsGetCurrentContext();
   CGPathRef cgPath = path.CGPath;
   BOOL    isHit = NO;
 
   // Determine the drawing mode to use. Default to
   // detecting hits on the stroked portion of the path.
   CGPathDrawingMode mode = kCGPathStroke;
   if (inFill)
   {
      // Look for hits in the fill area of the path instead.
      if (path.usesEvenOddFillRule)
         mode = kCGPathEOFill;
      else
         mode = kCGPathFill;
   }
 
   // Save the graphics state so that the path can be
   // removed later.
   CGContextSaveGState(context);
   CGContextAddPath(context, cgPath);
 
   // Do the hit detection.
   isHit = CGContextPathContainsPoint(context, point, mode);
 
   CGContextRestoreGState(context);
 
   return isHit;
}
  • 如上显示了一个测试指定点是否与指定路径相交的方法。inFill参数允许调用者指定是否应该根据路径的填充部分或描边部分测试该点。调用方传入的路径必须包含一个或多个封闭子路径,以便命中检测成功。

使用测试

绘制了个类似气泡的玩意

- (void)addQuadCurveToPoint:(CGPoint)endPoint 
               controlPoint:(CGPoint)controlPoint;

因为addQuadCurveToPoint中是设置的endPoint,所以上图中的弧点8应是 3的位置,弧点9应是起点位置


- (void)drawRect:(CGRect)rect
{
    UIBezierPath *aPath = [UIBezierPath bezierPath];
    [aPath moveToPoint:CGPointMake(50, 50)]; //起点
    [aPath addLineToPoint:CGPointMake(150, 50)]; //2 弧线起点
    [aPath addQuadCurveToPoint:CGPointMake(150, 100) controlPoint:CGPointMake(185, 75)]; //8圆点 10控制点 弧线
    [aPath addLineToPoint:CGPointMake(100, 100)];//4 尖尖角起点
    [aPath addLineToPoint:CGPointMake(85, 125)]; //5 尖尖角顶点
    [aPath addLineToPoint:CGPointMake(70, 100)]; //6 尖尖角终点
    [aPath addLineToPoint:CGPointMake(50, 100)]; //7 左边圆弧起点
    [aPath addQuadCurveToPoint:CGPointMake(50, 50) controlPoint:CGPointMake(15, 75)]; // 9圆点 11控制点 圆弧
    [aPath closePath]; // 闭合图形
    aPath.lineJoinStyle = kCGLineJoinRound;
    aPath.lineCapStyle = kCGLineCapRound;
    [[UIColor yellowColor] setStroke];
    [[UIColor purpleColor] setFill];
    
    CGContextRef aref = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(aref, 50, 50);
    aPath.lineWidth = 1;
    [aPath fill];
    [aPath stroke];
}

你可能感兴趣的:(OC,个人笔记,ios)