2013-03-26 15 views
7

używam tego kodu, aby zastosować warstwę UIView:Stosując maskę CAShapeLayer do UIView

mask = [[CAShapeLayer alloc] init]; 
mask.frame = baseView.layer.bounds; 
CGRect biggerRect = CGRectMake(mask.frame.origin.x, mask.frame.origin.y, mask.frame.size.width, mask.frame.size.height); 
CGRect smallerRect = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f); 

UIBezierPath *maskPath = [UIBezierPath bezierPath]; 
[maskPath moveToPoint:CGPointMake(CGRectGetMinX(biggerRect), CGRectGetMinY(biggerRect))]; 
[maskPath addLineToPoint:CGPointMake(CGRectGetMinX(biggerRect), CGRectGetMaxY(biggerRect))]; 
[maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(biggerRect), CGRectGetMaxY(biggerRect))]; 
[maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(biggerRect), CGRectGetMinY(biggerRect))]; 
[maskPath addLineToPoint:CGPointMake(CGRectGetMinX(biggerRect), CGRectGetMinY(biggerRect))]; 

[maskPath moveToPoint:CGPointMake(CGRectGetMinX(smallerRect), CGRectGetMinY(smallerRect))]; 
[maskPath addLineToPoint:CGPointMake(CGRectGetMinX(smallerRect), CGRectGetMaxY(smallerRect))]; 
[maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(smallerRect), CGRectGetMaxY(smallerRect))]; 
[maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(smallerRect), CGRectGetMinY(smallerRect))]; 
[maskPath addLineToPoint:CGPointMake(CGRectGetMinX(smallerRect), CGRectGetMinY(smallerRect))]; 

mask.path = maskPath.CGPath; 
[mask setFillRule:kCAFillRuleEvenOdd]; 
mask.fillColor = [[UIColor blackColor] CGColor]; 
baseView.layer.mask = mask; 

Ponieważ prostokąt chcę wyciąć zmian, byłem wonderning czy istnieje szybki sposób zmienić rozmiar maski zamiast usuwania jej z interfejsu użytkownika i ponownego jej stosowania w różnych wymiarach:

np.

[mask removeFromSuperlayer]; 

i ...

mask = [[CAShapeLayer alloc] init]; 
mask.frame = baseView.layer.bounds; 
CGRect biggerRect = CGRectMake(mask.frame.origin.x, mask.frame.origin.y, mask.frame.size.width, mask.frame.size.height); 
CGRect smallerRect = CGRectMake(0.0f, 100.0f, 200.0f, 200.0f); 

UIBezierPath *maskPath = [UIBezierPath bezierPath]; 
[maskPath moveToPoint:CGPointMake(CGRectGetMinX(biggerRect), CGRectGetMinY(biggerRect))]; 
[maskPath addLineToPoint:CGPointMake(CGRectGetMinX(biggerRect), CGRectGetMaxY(biggerRect))]; 
[maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(biggerRect), CGRectGetMaxY(biggerRect))]; 
[maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(biggerRect), CGRectGetMinY(biggerRect))]; 
[maskPath addLineToPoint:CGPointMake(CGRectGetMinX(biggerRect), CGRectGetMinY(biggerRect))]; 

[maskPath moveToPoint:CGPointMake(CGRectGetMinX(smallerRect), CGRectGetMinY(smallerRect))]; 
[maskPath addLineToPoint:CGPointMake(CGRectGetMinX(smallerRect), CGRectGetMaxY(smallerRect))]; 
[maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(smallerRect), CGRectGetMaxY(smallerRect))]; 
[maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(smallerRect), CGRectGetMinY(smallerRect))]; 
[maskPath addLineToPoint:CGPointMake(CGRectGetMinX(smallerRect), CGRectGetMinY(smallerRect))]; 

mask.path = maskPath.CGPath; 
[mask setFillRule:kCAFillRuleEvenOdd]; 
mask.fillColor = [[UIColor blackColor] CGColor]; 
baseView.layer.mask = mask; 

Odpowiedz

10

Jeśli pytasz, czy można przekształcić maskę bez konieczności narysować ścieżkę za każdym razem, niestety nie. Możesz zachować kształt maski taki sam i dokonywać przekształceń na masce, ustawiając właściwość transform obiektu, ale jeśli potrzebujesz maski, aby uzyskać inny kształt, będziesz musiał narysować ten kształt, tworząc nową ścieżkę. ALE nie trzeba wyjmować maski z UIView i tworzyć zupełnie nowej za każdym razem, gdy trzeba zmienić jej kształt. Po prostu ustawiając właściwość CAShapeLayer path gdy jeszcze maskowania UIView jest wystarczająca do zmiany nastąpić:

- (void)remask 
{ 
    CAShapeLayer *mask = (CAShapeLayer *)self.view.layer.mask; 

    CGRect biggerRect = CGRectMake(mask.frame.origin.x, mask.frame.origin.y, mask.frame.size.width, mask.frame.size.height); 
    CGRect smallerRect = CGRectMake(0.0f, 100.0f, 200.0f, 200.0f); 

    UIBezierPath *maskPath = [UIBezierPath bezierPath]; 
    [maskPath moveToPoint:CGPointMake(CGRectGetMinX(biggerRect), CGRectGetMinY(biggerRect))]; 
    [maskPath addLineToPoint:CGPointMake(CGRectGetMinX(biggerRect), CGRectGetMaxY(biggerRect))]; 
    [maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(biggerRect), CGRectGetMaxY(biggerRect))]; 
    [maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(biggerRect), CGRectGetMinY(biggerRect))]; 
    [maskPath addLineToPoint:CGPointMake(CGRectGetMinX(biggerRect), CGRectGetMinY(biggerRect))]; 

    [maskPath moveToPoint:CGPointMake(CGRectGetMinX(smallerRect), CGRectGetMinY(smallerRect))]; 
    [maskPath addLineToPoint:CGPointMake(CGRectGetMinX(smallerRect), CGRectGetMaxY(smallerRect))]; 
    [maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(smallerRect), CGRectGetMaxY(smallerRect))]; 
    [maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(smallerRect), CGRectGetMinY(smallerRect))]; 
    [maskPath addLineToPoint:CGPointMake(CGRectGetMinX(smallerRect), CGRectGetMinY(smallerRect))]; 

    mask.path = maskPath.CGPath; 
} 

Na marginesie, jesteś świadom, że zamiast rysowania każdego prostokąta ręcznie można utworzyć ścieżka maskująca przy użyciu następującego kodu:

mask = [[CAShapeLayer alloc] init]; 
mask.frame = baseView.layer.bounds; 
CGRect biggerRect = CGRectMake(mask.frame.origin.x, mask.frame.origin.y, mask.frame.size.width, mask.frame.size.height); 
CGRect smallerRect = CGRectMake(0.0f, 100.0f, 200.0f, 200.0f); 

CGMutablePathRef maskPath = CGPathCreateMutable(); 
CGPathAddRect(maskPath, NULL, biggerRect); 
CGPathAddRect(maskPath, NULL, smallerRect); 

mask.path = maskPath; 
[mask setFillRule:kCAFillRuleEvenOdd]; 
mask.fillColor = [[UIColor blackColor] CGColor]; 
baseView.layer.mask = mask; 

CGPathRelease(maskPath); 

Pomyślałem, że po prostu wskażę, jak może być wygodniej dla Ciebie w przyszłości.

+0

Wygląda świetnie, ale jaka jest różnica? – Alessandro

+3

@Alessandro Cóż, wynik jest identyczny, ale poza tym: mniej linii kodu + prawdopodobnie bardziej czytelne/oczywiste + używa lekkiego API C zamiast "ciężkiego" obiektu 'UIBezierPath', więc prawdopodobnie jest trochę bardziej wydajny. Wystarczy wskazać funkcje "AddRect" dla wygody w przyszłości. W rzeczywistości po prostu potrzebowałem czegoś, co towarzyszyłoby złym wieściom z mojej odpowiedzi, że chęć zrobienia nie jest bezpośrednio możliwa haha. –