it-swarm.com.de

Wie zeichne ich einen Schatten unter einer UIView?

Ich versuche in Cocoa Touch einen Schatten unter dem unteren Rand einer UIView zu zeichnen. Ich verstehe, dass ich CGContextSetShadow() verwenden sollte, um den Schatten zu zeichnen, aber die Quartz 2D-Programmieranleitung ist etwas vage:

  1. Speichern Sie den Grafikstatus.
  2. Rufen Sie die Funktion CGContextSetShadow auf und übergeben Sie die entsprechenden Werte.
  3. Führen Sie alle Zeichnungen aus, auf die Sie Schatten anwenden möchten.
  4. Stellen Sie den Grafikstatus wieder her

Ich habe in einer UIView-Unterklasse Folgendes versucht:

- (void)drawRect:(CGRect)rect {
    CGContextRef currentContext = UIGraphicsGetCurrentContext();
    CGContextSaveGState(currentContext);
    CGContextSetShadow(currentContext, CGSizeMake(-15, 20), 5);
    CGContextRestoreGState(currentContext);
    [super drawRect: rect];
}

..aber das funktioniert nicht für mich und ich bin ein bisschen fest geblieben (a) wohin ich als nächstes gehen soll und (b) ob es etwas gibt, was ich mit meiner UIView tun muss, um diese Arbeit zu machen?

339
Fraser Speirs

Speichern Sie in Ihrem aktuellen Code die Variable GState des aktuellen Kontextes, konfigurieren Sie sie, um einen Schatten zu zeichnen. Dann rufen Sie schließlich die Implementierung der Superklasse von drawRect: auf.

Jede Zeichnung, die von der Schatteneinstellung betroffen sein sollte, muss ausgeführt werden nach dem

CGContextSetShadow(currentContext, CGSizeMake(-15, 20), 5);

aber vor

CGContextRestoreGState(currentContext);

Wenn Sie also möchten, dass der drawRect: der Superklasse in einen Schatten 'eingebunden' wird, wie wäre es dann, wenn Sie Ihren Code so umstellen?

- (void)drawRect:(CGRect)rect {
    CGContextRef currentContext = UIGraphicsGetCurrentContext();
    CGContextSaveGState(currentContext);
    CGContextSetShadow(currentContext, CGSizeMake(-15, 20), 5);
    [super drawRect: rect];
    CGContextRestoreGState(currentContext);
}
93

Bei weitem einfacher ist es, einige Layer-Attribute der Ansicht bei der Initialisierung festzulegen:

self.layer.masksToBounds = NO;
self.layer.shadowOffset = CGSizeMake(-15, 20);
self.layer.shadowRadius = 5;
self.layer.shadowOpacity = 0.5;

Sie müssen QuartzCore importieren.

#import <QuartzCore/QuartzCore.h>
781
ollie
self.layer.masksToBounds = NO;
self.layer.cornerRadius = 8; // if you like rounded corners
self.layer.shadowOffset = CGSizeMake(-15, 20);
self.layer.shadowRadius = 5;
self.layer.shadowOpacity = 0.5;

Dies wird die Anwendung verlangsamen. Das Hinzufügen der folgenden Zeile kann die Leistung verbessern, solange Ihre Ansicht sichtbar rechteckig ist:

self.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.bounds].CGPath;
230
ZYiOS

Gleiche Lösung, aber nur zur Erinnerung: Sie können den Schatten direkt im Storyboard definieren.

Ex:

enter image description here

154
Antzi

Sie können dies versuchen .... Sie können mit den Werten spielen .. _ Die shadowRadius bestimmt die Menge der Unschärfe. shadowOffset gibt an, wohin der Schatten geht.

Swift 2.0

let radius: CGFloat = demoView.frame.width / 2.0 //change it to .height if you need spread for height
let shadowPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 2.1 * radius, height: demoView.frame.height))
//Change 2.1 to amount of spread you need and for height replace the code for height

demoView.layer.cornerRadius = 2
demoView.layer.shadowColor = UIColor.blackColor().CGColor
demoView.layer.shadowOffset = CGSize(width: 0.5, height: 0.4)  //Here you control x and y
demoView.layer.shadowOpacity = 0.5
demoView.layer.shadowRadius = 5.0 //Here your control your blur
demoView.layer.masksToBounds =  false
demoView.layer.shadowPath = shadowPath.CGPath

Swift 3.0

let radius: CGFloat = demoView.frame.width / 2.0 //change it to .height if you need spread for height 
let shadowPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 2.1 * radius, height: demoView.frame.height)) 
//Change 2.1 to amount of spread you need and for height replace the code for height

demoView.layer.cornerRadius = 2
demoView.layer.shadowColor = UIColor.black.cgColor
demoView.layer.shadowOffset = CGSize(width: 0.5, height: 0.4)  //Here you control x and y
demoView.layer.shadowOpacity = 0.5
demoView.layer.shadowRadius = 5.0 //Here your control your blur
demoView.layer.masksToBounds =  false
demoView.layer.shadowPath = shadowPath.cgPath

Beispiel mit Aufstrich

 Example with spread

Einen grundlegenden Schatten erzeugen 

    demoView.layer.cornerRadius = 2
    demoView.layer.shadowColor = UIColor.blackColor().CGColor
    demoView.layer.shadowOffset = CGSizeMake(0.5, 4.0); //Here your control your spread
    demoView.layer.shadowOpacity = 0.5 
    demoView.layer.shadowRadius = 5.0 //Here your control your blur

Grundlegendes Schattenbeispiel in Swift 2.0

 OUTPUT

40
O-mkar

Einfache und saubere Lösung mit Interface Builder

Fügen Sie eine Datei mit dem Namen UIView.Swift in Ihrem Projekt hinzu (oder fügen Sie diese einfach in eine beliebige Datei ein):

import UIKit

@IBDesignable extension UIView {

    /* The color of the shadow. Defaults to opaque black. Colors created
    * from patterns are currently NOT supported. Animatable. */
    @IBInspectable var shadowColor: UIColor? {
        set {
            layer.shadowColor = newValue!.CGColor
        }
        get {
            if let color = layer.shadowColor {
                return UIColor(CGColor:color)
            }
            else {
                return nil
            }
        }
    }

    /* The opacity of the shadow. Defaults to 0. Specifying a value outside the
    * [0,1] range will give undefined results. Animatable. */
    @IBInspectable var shadowOpacity: Float {
        set {
            layer.shadowOpacity = newValue
        }
        get {
            return layer.shadowOpacity
        }
    }

    /* The shadow offset. Defaults to (0, -3). Animatable. */
    @IBInspectable var shadowOffset: CGPoint {
        set {
            layer.shadowOffset = CGSize(width: newValue.x, height: newValue.y)
        }
        get {
            return CGPoint(x: layer.shadowOffset.width, y:layer.shadowOffset.height)
        }
    }

    /* The blur radius used to create the shadow. Defaults to 3. Animatable. */
    @IBInspectable var shadowRadius: CGFloat {
        set {
            layer.shadowRadius = newValue
        }
        get {
            return layer.shadowRadius
        }
    }
}

Dann ist dies im Interface Builder für jede Ansicht im Bedienfeld Dienstprogramme> Inspektor Attribute verfügbar:

 Utilities Panel

Sie können den Schatten jetzt einfach einstellen.

Anmerkungen:
- Der Schatten erscheint in IB nicht nur zur Laufzeit.
- Wie Mazen Kasser sagte

Für diejenigen, die dies nicht erreichen konnten, [...] stellen Sie sicher, dass Clip-Subviews (clipsToBounds) nicht aktiviert sind

18
Axel Guilmin

Ich benutze dies als Teil meiner Werkzeuge. Damit können wir nicht nur Schatten setzen, sondern auch eine abgerundete Ecke für jede UIView erhalten. Sie können auch festlegen, welchen Farbschatten Sie bevorzugen. Normalerweise wird Schwarz bevorzugt, aber manchmal, wenn der Hintergrund nicht weiß ist, möchten Sie vielleicht etwas anderes. Hier ist was ich benutze -

in utils.m
+ (void)roundedLayer:(CALayer *)viewLayer 
              radius:(float)r 
              shadow:(BOOL)s
{
    [viewLayer setMasksToBounds:YES];
    [viewLayer setCornerRadius:r];        
    [viewLayer setBorderColor:[RGB(180, 180, 180) CGColor]];
    [viewLayer setBorderWidth:1.0f];
    if(s)
    {
        [viewLayer setShadowColor:[RGB(0, 0, 0) CGColor]];
        [viewLayer setShadowOffset:CGSizeMake(0, 0)];
        [viewLayer setShadowOpacity:1];
        [viewLayer setShadowRadius:2.0];
    }
    return;
}

Um dies zu verwenden, müssen wir das - [utils roundedLayer:yourview.layer radius:5.0f shadow:YES]; - aufrufen.

13

Swift 3

extension UIView {
    func installShadow() {
        layer.cornerRadius = 2
        layer.masksToBounds = false
        layer.shadowColor = UIColor.black.cgColor
        layer.shadowOffset = CGSize(width: 0, height: 1)
        layer.shadowOpacity = 0.45
        layer.shadowPath = UIBezierPath(rect: bounds).cgPath
        layer.shadowRadius = 1.0
    }
}
7
neoneye

Für diejenigen, die dies nicht erfolgreich ausgeführt haben (als ich selbst!), Nachdem Sie alle Antworten ausprobiert haben, stellen Sie sicher, dass Subviews unter Clipsen im Attribut-Inspektor nicht aktiviert ist ...

3
Mazen Kasser

Wenn Sie StoryBoard verwenden möchten und die Laufzeitattribute nicht weiter eingeben möchten, können Sie problemlos eine Erweiterung für Ansichten erstellen und diese im Storyboard verwenden.

Schritt 1. Erweiterung erstellen

extension UIView {

@IBInspectable var shadowRadius: CGFloat {
    get {
        return layer.shadowRadius
    }
    set {
        layer.shadowRadius = newValue
    }
}

@IBInspectable var shadowOpacity: Float {
    get {
        return layer.shadowOpacity
    }
    set {
        layer.shadowOpacity = newValue
    }
}

@IBInspectable var shadowOffset: CGSize {
    get {
        return layer.shadowOffset
    }
    set {
        layer.shadowOffset = newValue
    }
}

@IBInspectable var maskToBound: Bool {
    get {
        return layer.masksToBounds
    }
    set {
        layer.masksToBounds = newValue
    }
}
}

schritt 2. Sie können diese Attribute jetzt im Storyboard storyboard image

2
king_T

Alle Antworten alle gut, aber ich möchte noch einen Punkt hinzufügen 

Wenn Sie bei Tabellenzellen auf ein Problem stoßen. Wenn Sie eine neue Zelle dekomprimieren, besteht ein Missverhältnis im Schatten. In diesem Fall müssen Sie den Schattencode in einer layoutSubviews-Methode platzieren, damit er sich unter allen Bedingungen gut verhält.

-(void)layoutSubviews{
    [super layoutSubviews];

    [self.contentView setNeedsLayout];
    [self.contentView layoutIfNeeded];
    [VPShadow applyShadowView:self];
}

oder in ViewControllers für eine bestimmte Ansicht platzieren Sie den Schattencode in der folgenden Methode, damit er gut funktioniert

-(void)viewDidLayoutSubviews{
    [super viewDidLayoutSubviews];

    [self.viewShadow layoutIfNeeded];
    [VPShadow applyShadowView:self.viewShadow];
}

Ich habe meine Schattenimplementierung für neue Entwickler geändert, um eine allgemeinere Form von ex zu erhalten:

/*!
 @brief Add shadow to a view.

 @param layer CALayer of the view.

 */
+(void)applyShadowOnView:(CALayer *)layer OffsetX:(CGFloat)x OffsetY:(CGFloat)y blur:(CGFloat)radius opacity:(CGFloat)alpha RoundingCorners:(CGFloat)cornerRadius{
    UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRoundedRect:layer.bounds cornerRadius:cornerRadius];
    layer.masksToBounds = NO;
    layer.shadowColor = [UIColor blackColor].CGColor;
    layer.shadowOffset = CGSizeMake(x,y);// shadow x and y
    layer.shadowOpacity = alpha;
    layer.shadowRadius = radius;// blur effect
    layer.shadowPath = shadowPath.CGPath;
}
1
Vishal16

Sie können meine Hilfsfunktion für Schatten und Eckenradius wie folgt verwenden:

- (void)addShadowWithRadius:(CGFloat)shadowRadius withShadowOpacity:(CGFloat)shadowOpacity withShadowOffset:(CGSize)shadowOffset withShadowColor:(UIColor *)shadowColor withCornerRadius:(CGFloat)cornerRadius withBorderColor:(UIColor *)borderColor withBorderWidth:(CGFloat)borderWidth forView:(UIView *)view{

    // drop shadow
    [view.layer setShadowRadius:shadowRadius];
    [view.layer setShadowOpacity:shadowOpacity];
    [view.layer setShadowOffset:shadowOffset];
    [view.layer setShadowColor:shadowColor.CGColor];

    // border radius
    [view.layer setCornerRadius:cornerRadius];

    // border
    [view.layer setBorderColor:borderColor.CGColor];
    [view.layer setBorderWidth:borderWidth];
}

Hoffe es wird dir helfen !!!

1

Swift 3

self.paddingView.layer.masksToBounds = false
self.paddingView.layer.shadowOffset = CGSize(width: -15, height: 10)
self.paddingView.layer.shadowRadius = 5
self.paddingView.layer.shadowOpacity = 0.5
0
Josh O'Connor

Für Xamarianer sieht die Xamarin.iOS/C # -Version der Antwort wie folgt aus:

public override void DrawRect(CGRect area, UIViewPrintFormatter formatter)
{
    CGContext currentContext = UIGraphics.GetCurrentContext();
    currentContext.SaveState();
    currentContext.SetShadow(new CGSize(-15, 20), 5);
    base.DrawRect(area, formatter);
    currentContext.RestoreState();                
}

Der Hauptunterschied besteht darin, dass Sie eine Instanz von CGContext erwerben, in der Sie die entsprechenden Methoden direkt aufrufen.

0
Martin Zikmund