Frage

Ich versuche, einen Schatten unter dem unteren Rande eines UIView in Cocoa Touch zu ziehen. Ich verstehe, dass ich CGContextSetShadow() sollte den Schatten zu ziehen, aber die Quartz 2D Programmieranleitung ist ein wenig vage:

  1. Speichern Sie den Grafikzustand.
  2. Rufen Sie die Funktion CGContextSetShadow, die entsprechenden Werte übergeben.
  3. Führen Sie alle die Zeichnung, auf die Sie wollen Schatten anzuwenden.
  4. Wiederherstellen des Grafikzustand

Ich habe versucht, die folgend in einer UIView Unterklasse:

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

.. aber das ist nicht für mich arbeiten und ich bin ein bisschen stecken über (a), wo als nächstes gehen und (b), wenn es etwas, muss ich meine UIView tun, um diese Arbeit zu machen?

War es hilfreich?

Lösung

In Ihrem aktuellen Code, können Sie die GState des aktuellen Kontext speichern, konfigurieren Sie es einen Schatten zu ziehen .. und die Wiederherstellung es zu dem, was es war, bevor Sie es konfiguriert ist, einen Schatten zu zeichnen. Dann, endlich, rufen Sie die Umsetzung der übergeordneten Klasse von drawRect:.

Jede Zeichnung, die durch die Schatten Einstellung nicht betroffen sein sollte geschehen muss nach

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

aber vor

CGContextRestoreGState(currentContext);

Wenn Sie also die übergeordnete Klasse der drawRect: wollen in einem Schatten ‚gewickelt‘ werden, dann, wie wäre es, wenn Sie Ihren Code wie folgt neu anordnen?

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

Andere Tipps

Eine bei weitem einfacher Ansatz ist es, einige Ebenenattribute der Ansicht, bei der Initialisierung zu setzen:

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

Sie müssen Quartz importieren.

#import <QuartzCore/QuartzCore.h>
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 die Leistung verbessern können, solange Ihre Ansicht sichtbar rechteckig ist:

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

Die gleiche Lösung, sondern nur daran erinnern: Sie können den Schatten direkt in dem Storyboard definieren

.

Beispiel:

eingeben Bild Beschreibung hier

Sie können versuchen, diese .... Sie mit den Werten spielen kann. Die shadowRadius diktiert die Menge der Unschärfe. shadowOffset diktiert, wo 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 gespreiztem

 Beispiel mit ausgebreiteten

  

einen Grund Schatten erstellen

    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
  

Grund Schatten Beispiel in Swift 2.0

 OUTPUT

Einfache und saubere Lösung mit Interface Builder

Fügen Sie eine Datei mit dem Namen UIView.swift in Ihrem Projekt (oder auch nur diese Paste in einem beliebigen Datei):

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 wird dies im Interface Builder für jede Ansicht in dem Utilities-Panel verfügbar sein> Attribute Inspector:

 Utilities Panel

Sie können den Schatten jetzt einfach eingestellt.

Weitere Informationen:
 - Der Schatten erscheint nicht in IB, erst zur Laufzeit
.  - Wie Mazen Kasser sagte

  

Für diejenigen, die in immer dies versäumt arbeiten [...] stellen Sie sicher, Clip Subviews (clipsToBounds) ist nicht aktiviert

Ich benutze dies als Teil meiner utils. Damit können wir nicht nur Schatten gesetzt, sondern auch eine abgerundete Ecke für jede UIView bekommen kann. Auch Sie könnten festlegen, welche Farbe Sie bevorzugen Schatten. Normalerweise ist schwarz bevorzugt, aber manchmal, wenn der Hintergrund nicht weiß ist, könnte man etwas anderes will. Hier ist, was ich -

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 verwenden wir brauchen diese nennen - [utils roundedLayer:yourview.layer radius:5.0f shadow:YES];

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
    }
}

Wenn Sie möchten, Storyboard verwenden und würde nicht gerne Eingabe Laufzeit Attribute halten, können Sie leicht eine Erweiterung Ansichten erstellen können und machen sie in Storyboard verwendet werden.

Schritt 1. Erstellen Erweiterung

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 nun diese Attribute in Storyboard

Für diejenigen, die in immer dies versäumt zu arbeiten (wie mich!), Nachdem alle Antworten hier versuchen, nur um sicher machen Clip Subviews ist nicht im Attribute-Inspektor aktiviert ...

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

Sie können meine Nutzenfunktion für Schatten und Eckenradius erstellt, wie unten 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 Ihnen helfen !!!

Alle Antworten alles gut, aber ich möchte einen weiteren Punkt hinzufügen

Wenn Sie ein Problem auftreten, wenn Sie Tabellenzellen haben, Deque eine neue Zelle ein Konflikt im Schatten gibt es so in diesem Fall, müssen Sie Ihren Schatten-Code in einem layoutSubviews Verfahren zu platzieren, so dass es schön unter allen Bedingungen verhalten wird.

-(void)layoutSubviews{
    [super layoutSubviews];

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

oder in Viewcontrollers für bestimmte Ansicht Platz Schatten Code innerhalb der folgenden Methode so, dass es gut funktionieren

-(void)viewDidLayoutSubviews{
    [super viewDidLayoutSubviews];

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

Ich habe für verallgemeinerte Form ex meinen Schatten Implementierung für neue Entwickler geändert:

/*!
 @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;
}

Für Kerl Xamarians, die Xamarin.iOS / C # Version der Antwort würde wie folgt aussehen:

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 wesentliche Unterschied besteht darin, dass Sie eine Instanz von CGContext zu erwerben, auf dem Sie direkt die entsprechenden Methoden aufrufen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top