Как получить обратный путь UIBezierPath

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

(так много мне удалось запустить с помощью какого-то googling..)

У меня есть этот путь. Теперь я хочу заполнить обратную сторону этого пути, оставив эту часть и заполнив все остальное. Может ли кто-нибудь помочь мне с кодировкой. У меня мало информации об этом.

ПРОБЛЕМА

enter image description here

Область, отображаемая после использования Cemal Answer, ранее показывала только круг с красным штрихом.

NEW EDIT

- (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);
}

enter image description here

Ответ 1

Используйте bezierPathByReversingPath. Из документов (только для iOS 6.0+):

Создает и возвращает новый объект пути bezier с измененным содержимым текущего пути.

чтобы изменить ваш путь, вы просто:

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

Ответ 2

Здесь альтернатива, которая не требует полного изменения пути.

У вас есть часть представления, которое вы по сути хотите "вырезать":

clipped out

Предположим, вы хотите, чтобы белая область была [UIColor whiteColor] с 75% альфой. Вот как вы это делаете быстро:

  • Вы создаете новый подкласс 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 представления не должен включать альфа-компонент. Поэтому в вашем случае вы хотите, чтобы это было просто [UIColor whiteColor]. Затем вы применяете альфа-бит самостоятельно, вызывая [myView setAlpha:0.75].

Что здесь происходит: используется режим наложения, называемый "Destination Out". Математически это определяется как R = D*(1 - Sa), но в терминах непрофессионала это означает "Конечный образ, где целевое изображение непрозрачно, но исходное изображение является прозрачным и прозрачным в другом месте".

Таким образом, он будет использовать пункт назначения (то есть, что уже в контексте), где новый материал прозрачен (т.е. вне пути безье), а затем, когда путь безье будет непрозрачным, этот материал станет прозрачный. Однако материал назначения должен быть непрозрачным. Если это не непрозрачно, смешение не делает то, что вы хотите. Вот почему вам нужно предоставить непрозрачный UIColor, а затем сделать любую прозрачность, которую вы хотите, с видом напрямую.


Я сам это сделал с этими обстоятельствами:

  • в окне есть фон [UIColor greenColor]
  • fillColor - белый
  • punchedOutPath - это овал, который вставляет 10 точек из краев представления.
  • представление имеет alpha of 0.75

С приведенным выше кодом я получаю следующее:

enter image description here

Внутреннее пространство чисто зеленое, а снаружи - полупрозрачное наложение.


Обновление

Если ваше покрытие является изображением, вам нужно создать новое изображение. Но принцип тот же:

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.

Ответ 3

У меня есть два решения для вас.

  • Нарисуйте этот путь на CALayer. И используйте CALayer в качестве слоя маски для фактического CALayer.

  • Нарисуйте прямоугольник с размерами вашего кадра перед добавлением дуги.

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

Я бы использовал второе решение.:)

Ответ 4

Вы можете поместить это в одно экранное приложение в контроллер вида: он сделает желтый фон, а поверх него будет синий слой с овальной областью, вырезанной маской.

- (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 Вычитать путь