2013-08-21 16 views
11

Próbuję utworzyć etykietę (lub jakikolwiek inny widok w tej sprawie) z jednym zaokrąglonym rogiem i obrysem/obramowaniem. Mogę osiągnąć dawny stosując następujący kod:Skrypt zamaskowany CALayer w iOS

UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.label.bounds 
             byRoundingCorners:UIRectCornerBottomRight 
              cornerRadii:CGSizeMake(16.0f, 16.0f)]; 

CAShapeLayer *shape = [CAShapeLayer layer]; 
shape.frame = self.label.bounds; 
shape.path = maskPath.CGPath; 

self.label.layer.mask = shape; 

Który działa świetnie na zaokrąglonym narożniku, ale stosując następujący kod nie ma zastosowania skoku tak, jak chcę. Zamiast tego tworzy się czarny (lub cokolwiek innego, co backgroundColor z ustawiono na) kwadratowych border.

UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.label.bounds 
             byRoundingCorners:UIRectCornerBottomRight 
              cornerRadii:CGSizeMake(16.0f, 16.0f)]; 

CAShapeLayer *shape = [CAShapeLayer layer]; 
shape.frame = self.label.bounds; 
shape.path = maskPath.CGPath; 

// Add stroke 
shape.borderWidth = 1.0f; 
shape.borderColor = [UIColor whiteColor].CGColor; 

self.label.backgroundColor = [UIColor blackColor]; 
self.label.layer.mask = shape; 

Wszelkie sugestie, w jaki sposób można zastosować dowolną kolorową udar, który następuje zamaskowaną ścieżkę?

Odpowiedz

35

Jesteś na dobrej drodze z warstwą kształtu. Ale powinieneś mieć dwie różne warstwy. Najpierw warstwa maski jak w pierwszym przykładzie, która maskuje widok (obcina obszary, których nie chcesz widzieć). Upewnij się również, że nie używasz borderWidth i borderColor, ale obrys.

// 
// Create your mask first 
// 
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.label.bounds 
             byRoundingCorners:UIRectCornerBottomRight 
              cornerRadii:CGSizeMake(16.0f, 16.0f)]; 

CAShapeLayer *maskLayer = [CAShapeLayer layer]; 
maskLayer.frame = self.label.bounds; 
maskLayer.path = maskPath.CGPath; 
self.label.layer.mask = maskLayer;  

// 
// And then create the outline layer 
// 
CAShapeLayer *shape = [CAShapeLayer layer]; 
shape.frame = self.label.bounds; 
shape.path = maskPath.CGPath; 
shape.lineWidth = 3.0f; 
shape.strokeColor = [UIColor whiteColor].CGColor; 
shape.fillColor = [UIColor clearColor].CGColor; 
[self.label.layer addSublayer:shape]; 

Należy pamiętać, że ścieżka warstwy obrysu powinna znajdować się wewnątrz (mniejszej niż) ścieżki maski. W przeciwnym razie obrysowana ścieżka zostanie zamaskowana przez warstwę maski. Ustawiłem lineWith na 3, dzięki czemu widać połowę szerokości (1,5 px), a druga połowa będzie poza maską.

+0

Tego rodzaju prace, ale teraz tekst etykiety został pokryty warstwą "shape" :( –

+1

OK Udało mi się sprawić, żeby działało, nakładając maskę na 'UIView' i dodając' UILabel' jako wyskok. Bardzo dziękuję :) –

+8

StrokeLayer zakrywa etykietę, więc dodałem to, aby poprawić to. 'shape.fillColor = [UIColor clearColor] .CGColor' –

0

Jeśli masz podklasę CALayer, możesz utworzyć instancję z odpowiednią maską, a także zastąpić layoutSubLayers, aby dołączyć ramkę do tej maski.

Można to zrobić na kilka sposobów. Poniżej Ill zrób to, używając path danej maski i przypisując ją do właściwości klasy, która ma być użyta do skonstruowania nowej granicy w layoutSubLayers. Istnieje potencjał, że ta metoda mogłaby zostać wywołana wiele razy, więc ustawiłem również boolean, aby to śledzić. (Można również przypisać granicę jako właściwość klasy i usunąć/re-add każdorazowo Na razie używam sprawdzanie bool

Swift 3:..

class CustomLayer: CALayer { 

    private var path: CGPath? 
    private var borderSet: Bool = false 

    init(maskLayer: CAShapeLayer) { 
     super.init() 
     self.path = maskLayer.path 
     self.frame = maskLayer.frame 
     self.bounds = maskLayer.bounds 
     self.mask = maskLayer 
    } 

    override func layoutSublayers() { 

     let newBorder = CAShapeLayer() 

     newBorder.lineWidth = 12 
     newBorder.path = self.path 
     newBorder.strokeColor = UIColor.black.cgColor 
     newBorder.fillColor = nil 


     if(!borderSet) { 
      self.addSublayer(newBorder) 
      self.borderSet = true 
     } 

    } 

    required override init(layer: Any) { 
     super.init(layer: layer) 
    } 

    required init?(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 
}