28

Ich versuche, einen Schatten und einen Eckenradius auf einem Bild zu zeichnen. Ich kann sie einzeln hinzufügen, aber ich habe keine Möglichkeit, beide Effekte gleichzeitig hinzuzufügen. Ich füge einen Schatten hinzu mit:Kann keinen Eckenradius und keinen Schatten hinzufügen

[layer setShadowOffset:CGSizeMake(0, 3)]; 
[layer setShadowOpacity:0.4]; 
[layer setShadowRadius:3.0f]; 
[layer setShouldRasterize:YES]; 

Hier ist Schicht ein CALayer einer UIView Unterklasse. So funktioniert das, wenn ich gesetzt

[layer setMasksToBounds:NO]; 

nun einen Eckenradius hinzuzufügen ich dies tun:

[layer setCornerRadius:7.0f]; 

aber ich brauche für diesen MasksToBounds auf YES zu setzen, um zu arbeiten:

[layer setMasksToBounds:YES]; 

Gibt es auf jeden Fall kann ich diese beiden Effekte hinzufügen?

Vielen Dank für Ihre Zeit,

Denis

Antwort

57

Ja, ja, es gibt ...

Wenn Sie sowohl einen Eckenradius und einen Schlagschatten möchten, können Sie nicht aktivieren - masksToBounds, sondern legen Sie den Eckenradius fest und legen Sie den Bezier-Pfad des Schattens mit einem abgerundeten Rechteck fest. Halten Sie den Radius der beiden gleich:

[layer setShadowOffset:CGSizeMake(0, 3)]; 
[layer setShadowOpacity:0.4]; 
[layer setShadowRadius:3.0f]; 
[layer setShouldRasterize:YES]; 

[layer setCornerRadius:12.0f]; 
[layer setShadowPath: 
        [[UIBezierPath bezierPathWithRoundedRect:[self bounds] 
               cornerRadius:12.0f] CGPath]]; 

, Sie möchten die Leistung ohne -shouldRasterize Parameter überprüfen, sobald Sie den Schatten Pfad sind einstellen. Nachdem Sie einen Schattenpfad festgelegt haben, ist die Zeichnungsleistung in der Regel sehr gut.

UPDATE

ich dieses Problem nicht ausgesehen hatte schon eine ganze Weile in, aber es scheint, dass Sie nicht mehr shadowPath, um diese Arbeit zu bekommen setzen müssen. Einfach die cornerRadius und shadowOpacity Einstellung wird jetzt funktionieren. Ich denke das ist seit iOS5 der Fall (soweit ich das beurteilen kann). Die Bereitstellung dieses Updates ist wahrscheinlich unnötig, da das Einstellen dieser Parameter "einfach funktioniert", aber ich werde es für die Nachwelt bereitstellen. Zur Erinnerung, das ist jetzt alles, was Sie brauchen:

[layer setShadowOpacity:0.4]; 
[layer setCornerRadius:12.0f]; 

Wenn Sie noch bessere Leistung benötigen, können Sie voran gehen und setzen Sie den shouldRasterize Parameter auch:

[layer setShouldRasterize:YES]; 

Und Leistung gesprochen, es lohnt sich Beachten Sie, dass Sie, wenn Sie träge Animationen bemerken, die Technik des Festlegens des Schattenpfads verwenden möchten. Mit diesem Update wurde lediglich darauf hingewiesen, dass das Festlegen des Pfads nicht länger erforderlich ist, um gleichzeitig einen Eckenradius und einen Schatten anzuzeigen. Wenn die Leistung Priorität hat, verwenden Sie einen Pfad.

UPDATE 2

Da die Menschen scheinen Schwierigkeiten zu haben dies immer in einigen Fällen zu arbeiten, ich werde ein vollständigeres Code-Schnipsel hier posten aus einem Beispielprojekt I erstellt:

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    CALayer *layer = [CALayer layer]; 
    [layer setBounds:CGRectMake(0.0f, 0.0f, 100.0f, 200.0f)]; 
    [layer setPosition:[[self view] center]]; 
    [layer setBackgroundColor:[[UIColor lightGrayColor] CGColor]]; 
    [layer setShadowOpacity:0.55f]; 
    [layer setCornerRadius:8.0f]; 
    [layer setBorderWidth:1.0f]; 

    [[[self view] layer] addSublayer:layer]; 

    [[[self testView] layer] setShadowOpacity:0.55f]; 
    [[[self testView] layer] setShadowRadius:15.0f]; 
    [[[self testView] layer] setCornerRadius:8.0f]; 
    [[[self testView] layer] setBorderWidth:1.0f]; 
} 

Die testView ist eine UIView, die ich im Interface Builder hinzugefügt und eine Steckdose eingerichtet habe. Dies stellt sicher, dass es sowohl auf den Ebenen, die Sie explizit hinzufügen, als auch auf den Ebenen in den Unteransichten funktioniert.

Ich habe dies auf den Simulatoren für iOS5 bis iOS6.1 getestet. Es gibt dieses Ergebnis für mich in jedem von ihnen:

enter image description here

+1

Gibt es irgendeinen Grund nicht shouldRasterize auf YES zu setzen? – memmons

+2

Es hängt davon ab, wie oft Sie die Ebene aktualisieren. Wenn Sie es einmal festlegen und nicht erneut aktualisieren möchten, wird die Rasterung beschleunigt, wenn Sie den Layer animieren. Wenn der Inhalt der Ebene jedoch häufig aktualisiert wird, wird dieser Inhalt bei jeder Änderung des Inhalts als Bild dargestellt, was die Scrollleistung beeinträchtigen könnte (vorausgesetzt, Sie scrollen/animieren). –

+0

Benötigt ein Leerzeichen zwischen UIBezierPath und bezierPathWithRoundedRect. –

-2
view.layer.cornerRadius=4; 
[view.layer setMasksToBounds:YES]; 
[view.layer setShadowColor:SHADOW_COLOR]; 
[view.layer setShadowOpacity:4 ]; 
[view.layer setShadowRadius:4]; 
[view.layer setShadowOffset:0];  
[view.layer setShadowPath: [[UIBezierPath bezierPathWithRoundedRect:[view bounds] cornerRadius:CORNER_RADIUS] CGPath]]; 
view.layer.borderColor=[[UIColor lightGrayColor] colorWithAlphaComponent:.5].CGColor; 
view.layer.borderWidth=.4; 
+2

schrecklich. wird nicht funktionieren. – Liam

3

Der folgende Swift 3-Code zeigt, wie auf einem Bild unter Verwendung von CAShapeLayer und CALayer einen Schatten und einen Eckenradius zu ziehen.

import UIKit 

class ViewController: UIViewController { 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     // constants 
     let radius: CGFloat = 20, offset = 8 
     let rect = CGRect(x: 0, y: 0, width: 200, height: 200) 

     // roundedView 
     let roundedView = UIView() 
     view.addSubview(roundedView) 

     // shadow layer 
     let shadowLayer = CALayer() 
     shadowLayer.shadowColor = UIColor.darkGray.cgColor 
     shadowLayer.shadowPath = UIBezierPath(roundedRect: rect, cornerRadius: radius).cgPath 
     shadowLayer.shadowOffset = CGSize(width: offset, height: offset) 
     shadowLayer.shadowOpacity = 0.8 
     shadowLayer.shadowRadius = 2 
     roundedView.layer.addSublayer(shadowLayer) 

     // mask layer 
     let maskLayer = CAShapeLayer() 
     maskLayer.path = UIBezierPath(roundedRect: rect, cornerRadius: radius).cgPath 

     // image layer 
     let imageLayer = CALayer() 
     imageLayer.mask = maskLayer 
     imageLayer.frame = rect 
     imageLayer.contentsGravity = kCAGravityResizeAspectFill 
     imageLayer.contents = UIImage(named: "image")?.cgImage 
     roundedView.layer.addSublayer(imageLayer) 

     // auto layout 
     roundedView.translatesAutoresizingMaskIntoConstraints = false 
     roundedView.widthAnchor.constraint(equalToConstant: rect.width).isActive = true 
     roundedView.heightAnchor.constraint(equalToConstant: rect.height).isActive = true 
     roundedView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true 
     roundedView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true 
    } 

} 

Dieser Code erzeugt die folgende Anzeige:

enter image description here


Der vorherige Code kann in die folgenden schnellen Dateien Refactoring:

CustomView.swift

import UIKit 

class CustomView: UIView { 

    var imageLayer: CALayer! 
    var image: UIImage? { 
     didSet { refreshImage() } 
    } 

    override var intrinsicContentSize: 


     CGSize { 
     return CGSize(width: 200, height: 200) 
    } 

    func refreshImage() { 
     if let imageLayer = imageLayer, let image = image { 
      imageLayer.contents = image.cgImage 
     } 
    } 

    override func layoutSubviews() { 
     super.layoutSubviews() 

     if imageLayer == nil { 
      let radius: CGFloat = 20, offset: CGFloat = 8 

      let shadowLayer = CALayer() 
      shadowLayer.shadowColor = UIColor.darkGray.cgColor 
      shadowLayer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath 
      shadowLayer.shadowOffset = CGSize(width: offset, height: offset) 
      shadowLayer.shadowOpacity = 0.8 
      shadowLayer.shadowRadius = 2 
      layer.addSublayer(shadowLayer) 

      let maskLayer = CAShapeLayer() 
      maskLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath 

      imageLayer = CALayer() 
      imageLayer.mask = maskLayer 
      imageLayer.frame = bounds 
      imageLayer.backgroundColor = UIColor.red.cgColor 
      imageLayer.contentsGravity = kCAGravityResizeAspectFill 
      layer.addSublayer(imageLayer) 
     } 


     refreshImage() 
    } 

} 

ViewController.swift

import UIKit 

class ViewController: UIViewController { 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     let roundedView = CustomView() 
     roundedView.translatesAutoresizingMaskIntoConstraints = false 
     view.addSubview(roundedView) 

     // auto layout 
     let horizontalConstraint = roundedView.centerXAnchor.constraint(equalTo: view.centerXAnchor) 
     let verticalConstraint = roundedView.centerYAnchor.constraint(equalTo: view.centerYAnchor) 
     NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint]) 

     roundedView.image = UIImage(named: "image") 
    } 

} 

können Sie mehr Wege finden, um Bilder mit abgerundeten Ecken und Schatten auf diesem Github repo zu kombinieren.

2

Da ich ein UIButton mit einem Hintergrundbild verwenden, funktionierte keine dieser Antworten für mich. Ich bekomme entweder keine Schatten oder keine runden Kanten auf meinen Knöpfen.

Der einfachste Weg, in meinem Szenario war nur eine andere Sicht hinter der Schaltfläche hinzufügen und den Schatten, um es wie so hinzufügen:

button.clipsToBounds=YES; 
button.layer.cornerRadius = 25; 

UIView *shadowView = [[UIView alloc]initWithFrame:button.frame]; 

shadowView.backgroundColor = [UIColor whiteColor];//needs this to cast shadow 
shadowView.layer.cornerRadius = 25; 
shadowView.clipsToBounds = YES; 
shadowView.layer.masksToBounds = NO; 
shadowView.layer.shadowOffset = CGSizeMake(0, 2); 
shadowView.layer.shadowRadius = 1; 
shadowView.layer.shadowOpacity = 0.2; 


[[button superview]addSubview:shadowView]; 
[[button superview]bringSubviewToFront:button]; 
Verwandte Themen