uiview с маскированием клипа с помощью CAShapeLayer и UIBezierPath

У меня проблема с обрезкой представления с помощью CAShapeLayer-UIBezierPath , я хочу обрезать содержимое, но в итоге получаю штрих (кадр) с этим UIBezierPath , это мой код

UIBezierPath *path2Path = [UIBezierPath bezierPath];
[path2Path moveToPoint:CGPointMake(206.745, 0)];
[path2Path addLineToPoint:CGPointMake(206.745, 97.613)];
[path2Path addLineToPoint:CGPointMake(0, 97.613)];
[path2Path addLineToPoint:CGPointMake(0, 0)];
[path2Path addLineToPoint:CGPointMake(87.28, 0)];
[path2Path addCurveToPoint:CGPointMake(103.808, 12.118) controlPoint1:CGPointMake(87.28, 0) controlPoint2:CGPointMake(86.555, 12.118)];
[path2Path addCurveToPoint:CGPointMake(119.466, 0) controlPoint1:CGPointMake(121.061, 12.118) controlPoint2:CGPointMake(119.466, 0)];
[path2Path addLineToPoint:CGPointMake(206.745, 0)];
[path2Path closePath];

[path2Path addClip];

CAShapeLayer *pathLayer = [CAShapeLayer layer];
pathLayer.frame=MYVIEW.bounds;
pathLayer.path = path2Path.CGPath;

pathLayer.strokeColor = [[UIColor blackColor] CGColor];
pathLayer.fillColor = [[UIColor clearColor] CGColor];

pathLayer.fillRule=kCAFillRuleEvenOdd;
[MYVIEW.layer setMask:pathLayer];
[MYVIEW.layer setMasksToBounds:YES];

MYVIEW.backgroundColor=[UIColor greenColor];

Результатом этого кода является просто зеленая линия штриха, границы пусты, например, http://i.stack.imgur.com/aehdo.png

Однако я хочу сделать границы зелеными, обрезанными этим штрихом.


person Aproram    schedule 19.06.2015    source источник
comment
Вы хотите показать единственную часть изображения внутри пути Безье. Верно?   -  person Rajesh Maurya    schedule 19.06.2015
comment
Да, точно . @RajeshMaurya   -  person Aproram    schedule 19.06.2015
comment
Могу я узнать? где ты пишешь код? В Viewcontroller или создан подкласс UIView.   -  person Rajesh Maurya    schedule 19.06.2015
comment
Вы добавили изображение в MYVIEW?   -  person Rajesh Maurya    schedule 19.06.2015
comment
@RajeshMaurya нет, это обычный вид с подвидами внутри (но пока у него просто цвет фона), я хочу обрезать подвиды или цвет фона для этого вида. основная проблема заключается в том, что маска применяется как штрих, а не как содержимое внутри представления   -  person Aproram    schedule 19.06.2015
comment
возможный дубликат Использовать путь Безье в качестве обтравочной маски   -  person Diogo T    schedule 07.07.2015


Ответы (3)


как сказал Роб Мэйофф, вы можете легко сделать это, установив маску слоя вашего представления на CAShapeLayer.

UIBezierPath *myClippingPath = ...
CAShapeLayer *mask           = [CAShapeLayer layer];
mask.path                    = myClippingPath.CGPath;
myView.layer.mask            = mask;

В Swift

let myClippingPath = UIBezierPath( ... )
let mask           = CAShapeLayer()
mask.path          = myClippingPath.CGPath
myView.layer.mask         = mask
person Blind Ninja    schedule 01.07.2015

Спасибо за ответы, ребята.

В случае, если кто-то не может найти подходящий ответ на SO для этого вопроса в течение нескольких часов, как я только что сделал, я собрал рабочий смысл в Swift 2.2 для маскирования/отсечения UIView с помощью CGRect/UIBezierPath:

https://gist.github.com/Flar49/7e977e81f1d2827f5fcd5c6c6a3c3d94

extension UIView {
    func mask(withRect rect: CGRect, inverse: Bool = false) {
        let path = UIBezierPath(rect: rect)
        let maskLayer = CAShapeLayer()

        if inverse {
            path.appendPath(UIBezierPath(rect: self.bounds))
            maskLayer.fillRule = kCAFillRuleEvenOdd
        }

        maskLayer.path = path.CGPath

        self.layer.mask = maskLayer
    }

    func mask(withPath path: UIBezierPath, inverse: Bool = false) {
        let path = path
        let maskLayer = CAShapeLayer()

        if inverse {
            path.appendPath(UIBezierPath(rect: self.bounds))
            maskLayer.fillRule = kCAFillRuleEvenOdd
        }

        maskLayer.path = path.CGPath

        self.layer.mask = maskLayer
    }
}

Применение:

let viewSize = targetView.bounds.size
let rect = CGRect(x: 20, y: 20, width: viewSize.width - 20*2, height: viewSize.height - 20*2)

// Cuts rectangle inside view, leaving 20pt borders around
targetView.mask(withRect: rect, inverse: true)

// Cuts 20pt borders around the view, keeping part inside rect intact
targetView.mask(withRect: rect)

Надеюсь, это сэкономит кому-то время в будущем :)

person Eugene Tartakovsky    schedule 07.10.2016

Вы даже можете улучшить ответ @Eugene (отличная работа, приятель!) с радиусом угла

  extension UIView {  
    func mask(withRect rect: CGRect, cornerRadius: CGFloat = 0, inverse: Bool = false) {
        let path = cornerRadius > 0 ?
            UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius) :
            UIBezierPath(rect: rect)
        let maskLayer = CAShapeLayer()

        if inverse {
            path.append(UIBezierPath(rect: bounds))
            maskLayer.fillRule = kCAFillRuleEvenOdd
        }

        maskLayer.path = path.cgPath

        self.layer.mask = maskLayer
    }
}
person oskarko    schedule 03.09.2020