14
self.myPath=[UIBezierPath bezierPathWithArcCenter:center 
                                           radius:200 
                                       startAngle:0 
                                         endAngle:180 
                                        clockwise:YES];

(这就是我能够通过一些网络搜索开始运行的)。

我有这条路。现在我想填充这条路径的反面,所以留下这部分并填充其他所有内容。我怎样才能完成编码?我没有太多这方面的信息。

问题

在此处输入图像描述

之前使用 Cemal Answer 后显示的区域仅显示一个带有红色笔划的圆圈。

编辑

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = [UIColor whiteColor];
        self.punchedOutPath =  
         [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 50, 400, 400)];
        self.fillColor = [UIColor redColor];
        self.alpha = 0.8;
    }
    return self;
}

- (void)drawRect:(CGRect)rect
{
    [[self fillColor] set];
    UIRectFill(rect);

    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextSetBlendMode(ctx, kCGBlendModeDestinationOut);

    [[self punchedOutPath] fill];

    CGContextSetBlendMode(ctx, kCGBlendModeNormal);
}

在此处输入图像描述

4

4 回答 4

21

使用bezierPathByReversingPath. 来自文档(仅限 iOS 6.0+):

创建并返回一个新的贝塞尔路径对象,其内容与当前路径的内容相反。

所以要扭转你的道路,你只需:

UIBezierPath* aPath = [UIBezierPath bezierPathWithArcCenter:center
                                                     radius:200
                                                 startAngle:0
                                                   endAngle:180
                                                  clockwise:YES];
self.myPath = [aPath bezierPathByReversingPath];
于 2012-09-10T07:31:28.427 回答
13

这是一个根本不需要反转路径的替代方案。

您实际上想要“剪掉”视图的一部分:

剪掉

假设您希望白色区域[UIColor whiteColor]具有 75% 的 alpha。以下是您快速完成的方法:

  • 您创建一个新的UIView子类。
  • 此视图有两个属性:

    @property (retain) UIColor *fillColor;
    @property (retain) UIBezierPath *punchedOutPath;
    
  • 你重写它的-drawRect:方法来做到这一点:

    - (void)drawRect:(CGRect)rect {
      [[self fillColor] set];
      UIRectFill(rect);
    
      CGContextRef ctx = UIGraphicsGetCurrentContext();
      CGContextSetBlendMode(ctx, kCGBlendModeDestinationOut);
    
      [[self punchedOutPath] fill];
    
      CGContextSetBlendMode(ctx, kCGBlendModeNormal);
    }
    

这里有一个警告:fillColor视图的不能包含 alpha 组件。所以在你的情况下,你希望它只是[UIColor whiteColor]. 然后,您通过调用自己应用 alpha 位[myView setAlpha:0.75]

这里发生了什么:这是使用一种名为“Destination Out”的混合模式。在数学上它被定义为R = D*(1 - Sa),但用外行的话来说,它的意思是“目标图像不透明但源图像透明的目标图像,并且在其他地方透明。”

所以它将使用目的地(即,已经在上下文中的东西),只要东西是透明的(即在贝塞尔路径之外),然后在贝塞尔路径不透明的地方,这些东西就会变得透明。但是,目标内容必须已经是opaque。如果它不是不透明的,则混合不会达到您想要的效果。这就是为什么你必须提供一个不透明的UIColor,然后直接对视图进行任何你想要的透明度。


我自己运行了这个,在这些情况下:

  • 窗口有[UIColor greenColor]背景
  • fillColor白色的
  • punchedOutPath是一个椭圆,距离视图边缘 10 个点。
  • 视图有alpha一个0.75

使用上面的代码,我得到了这个:

在此处输入图像描述

内部是纯绿色,外部有半透明覆盖。


更新

如果您的覆盖物是图像,那么您需要创建一个新图像。但原理是一样的:

UIImage* ImageByPunchingPathOutOfImage(UIImage *image, UIBezierPath *path) {
  UIGraphicsBeginImageContextWithOptions([image size], YES, [image scale]);

  [image drawAtPoint:CGPointZero];

  CGContextRef ctx = UIGraphicsGetCurrentContext();
  CGContextSetBlendMode(ctx, kCGBlendModeDestinationOut);
  [path fill];


  UIImage *final = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();
  return final;
}

然后,您将获取此函数的结果并将其放入UIImageView.

于 2012-06-29T03:21:13.897 回答
3

您可以将其放入视图控制器中的单屏应用程序中:它将创建一个黄色背景视图和一个蓝色层,其顶部有一个被蒙版切割的椭圆形区域。

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    // create a yellow background
    UIView *bg = [[UIView alloc] initWithFrame:self.view.bounds];
    bg.backgroundColor = [UIColor yellowColor];
    [self.view addSubview:bg];    

    // create the mask that will be applied to the layer on top of the 
    // yellow background
    CAShapeLayer *maskLayer = [CAShapeLayer layer];
    maskLayer.fillRule = kCAFillRuleEvenOdd;
    maskLayer.frame = self.view.frame;

    // create the paths that define the mask
    UIBezierPath *maskLayerPath = [UIBezierPath bezierPath];
    [maskLayerPath appendPath:[UIBezierPath bezierPathWithRect:CGRectInset(self.view.bounds, 20, 20)]];
    // here you can play around with paths :)
//    [maskLayerPath appendPath:[UIBezierPath bezierPathWithOvalInRect:(CGRect){{80, 80}, {140, 190}}]];
    [maskLayerPath appendPath:[UIBezierPath bezierPathWithOvalInRect:(CGRect){{100, 100}, {100, 150}}]];
    maskLayer.path = maskLayerPath.CGPath;

    // create the layer on top of the yellow background
    CALayer *imageLayer = [CALayer layer];
    imageLayer.frame = self.view.layer.bounds;
    imageLayer.backgroundColor = [[UIColor blueColor] CGColor];

    // apply the mask to the layer
    imageLayer.mask = maskLayer;
    [self.view.layer addSublayer:imageLayer];

}

这也可以回答这个问题:UIBezierPath Subtract Path

于 2013-03-07T12:20:38.657 回答
2

我有两个解决方案给你。

  1. CALayer. 并将其CALayer用作您实际的遮罩层CALayer

  2. 在添加圆弧之前绘制一个具有框架大小的矩形。

    UIBezierPath *path = [UIBezierPath bezierPathWithRect:view.frame];
    [path addArcWithCenter:center 
                    radius:200 
                startAngle:0 
                  endAngle:2*M_PI 
                 clockwise:YES];
    

我会使用第二种解决方案。:)

于 2012-06-25T14:42:40.803 回答