webentwicklung-frage-antwort-db.com.de

Wie füge ich meinem UIView am besten einen Schlagschatten hinzu?

Ich versuche, Ansichten, die übereinander geschichtet sind, einen Schlagschatten hinzuzufügen. Die Ansichten werden ausgeblendet, sodass Inhalte in anderen Ansichten angezeigt werden. In diesem Sinne möchte ich view.clipsToBounds Auf ON setzen, wenn die Ansichten angezeigt werden reduzieren ihren Inhalt wird abgeschnitten.

Dies scheint es mir schwer gemacht zu haben, den Ebenen einen Schlagschatten hinzuzufügen, da die Schatten auch abgeschnitten werden, wenn ich clipsToBounds einschalte.

Ich habe versucht, view.frame Und view.bounds Zu manipulieren, um dem Frame einen Schlagschatten hinzuzufügen, aber die Begrenzungen dürfen groß genug sein, um ihn zu umfassen, aber ich hatte kein Glück damit.

Hier ist der Code, mit dem ich einen Schatten hinzufüge (dies funktioniert nur mit clipsToBounds OFF wie gezeigt)

view.clipsToBounds = NO;
view.layer.shadowColor = [[UIColor blackColor] CGColor];
view.layer.shadowOffset = CGSizeMake(0,5);
view.layer.shadowOpacity = 0.5;

Hier ist ein Screenshot des Schattens, der auf die oberste hellste graue Ebene angewendet wird. Hoffentlich gibt dies eine Vorstellung davon, wie sich mein Inhalt überlappt, wenn clipsToBounds deaktiviert ist.

Shadow Application.

Wie kann ich meinem UIView einen Schatten hinzufügen und meinen Inhalt beschneiden?

Bearbeiten: Ich wollte nur hinzufügen, dass ich auch mit Hintergrundbildern mit Schatten herumgespielt habe, was gut funktioniert, aber ich möchte immer noch die beste codierte Lösung dafür wissen.

103
Wez

Versuche dies:

UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRect:view.bounds];
view.layer.masksToBounds = NO;
view.layer.shadowColor = [UIColor blackColor].CGColor;
view.layer.shadowOffset = CGSizeMake(0.0f, 5.0f);
view.layer.shadowOpacity = 0.5f;
view.layer.shadowPath = shadowPath.CGPath;

Zuallererst: Das UIBezierPath, das als shadowPath verwendet wird, ist entscheidend. Wenn Sie es nicht verwenden, werden Sie möglicherweise zunächst keinen Unterschied bemerken, aber das aufmerksame Auge wird eine gewisse Verzögerung feststellen, die bei Ereignissen wie dem Drehen des Geräts und/oder ähnlichem auftritt. Es ist eine wichtige Leistung Tweak.

Bezüglich Ihres Problems speziell: Die wichtige Zeile ist view.layer.masksToBounds = NO. Es deaktiviert das Ausschneiden der Unterebenen der Ansichtsebene , die sich über die Grenzen der Ansicht hinaus erstrecken.

Für diejenigen, die sich fragen, was der Unterschied zwischen masksToBounds (auf der Ebene) und der eigenen clipToBounds -Eigenschaft der Ansicht ist: Es gibt eigentlich keine. Das Umschalten eines hat Auswirkungen auf das andere. Nur eine andere Abstraktionsebene.


Swift 2.2:

override func layoutSubviews()
{
    super.layoutSubviews()

    let shadowPath = UIBezierPath(rect: bounds)
    layer.masksToBounds = false
    layer.shadowColor = UIColor.blackColor().CGColor
    layer.shadowOffset = CGSizeMake(0.0, 5.0)
    layer.shadowOpacity = 0.5
    layer.shadowPath = shadowPath.CGPath
}

Swift 3:

override func layoutSubviews()
{
    super.layoutSubviews()

    let shadowPath = UIBezierPath(rect: bounds)
    layer.masksToBounds = false
    layer.shadowColor = UIColor.black.cgColor
    layer.shadowOffset = CGSize(width: 0.0, height: 5.0)
    layer.shadowOpacity = 0.5
    layer.shadowPath = shadowPath.cgPath
}
272
pkluz

Wasabis Antwort in Swift 2.3:

    let shadowPath = UIBezierPath(rect: view.bounds)
    view.layer.masksToBounds = false
    view.layer.shadowColor = UIColor.blackColor().CGColor
    view.layer.shadowOffset = CGSize(width: 0, height: 0.5)
    view.layer.shadowOpacity = 0.2
    view.layer.shadowPath = shadowPath.CGPath

Und in Swift 3/4:

    let shadowPath = UIBezierPath(rect: view.bounds)
    view.layer.masksToBounds = false
    view.layer.shadowColor = UIColor.black.cgColor
    view.layer.shadowOffset = CGSize(width: 0, height: 0.5)
    view.layer.shadowOpacity = 0.2
    view.layer.shadowPath = shadowPath.cgPath

Fügen Sie diesen Code in layoutSubviews () ein, wenn Sie AutoLayout verwenden.

62
Bart van Kuik

Der Trick besteht darin, die Eigenschaft masksToBounds des Layers Ihrer Ansicht richtig zu definieren:

view.layer.masksToBounds = NO;

und es sollte funktionieren.

( Quelle )

13
sergio

Sie können eine Erweiterung für UIView erstellen, um im Entwurfseditor auf diese Werte zuzugreifen

Shadow options in design editor

extension UIView{

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

    @IBInspectable var shadowColor: UIColor{
        get{
            return UIColor(cgColor: self.layer.shadowColor!)
        }
        set{
            self.layer.shadowColor = newValue.cgColor
        }
    }

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

    @IBInspectable var shadowOpacity: Float{
        get{
            return self.layer.shadowOpacity
        }
        set{
            self.layer.shadowOpacity = newValue
        }
    }
}
13
Chris Stillwell

Sie können Ihre Ansicht auch vom Storyboard aus mit Schatten versehen

enter image description here

6
pallavi

Auf viewWillLayoutSubviews:

override func viewWillLayoutSubviews() {
    sampleView.layer.masksToBounds =  false
    sampleView.layer.shadowColor = UIColor.darkGrayColor().CGColor;
    sampleView.layer.shadowOffset = CGSizeMake(2.0, 2.0)
    sampleView.layer.shadowOpacity = 1.0
}

Verwendung der Erweiterung von UIView:

extension UIView {

    func addDropShadowToView(targetView:UIView? ){
        targetView!.layer.masksToBounds =  false
        targetView!.layer.shadowColor = UIColor.darkGrayColor().CGColor;
        targetView!.layer.shadowOffset = CGSizeMake(2.0, 2.0)
        targetView!.layer.shadowOpacity = 1.0
    }
}

Verwendung:

sampleView.addDropShadowToView(sampleView)
1
A.G

Also ja, Sie sollten die shadowPath-Eigenschaft für die Leistung bevorzugen, aber auch: Aus der Header-Datei von CALayer.shadowPath

Wenn Sie den Pfad explizit mit dieser Eigenschaft angeben, wird in der Regel * die Renderleistung verbessert, und derselbe Pfad * wird über mehrere Ebenen hinweg referenziert

Ein weniger bekannter Trick besteht darin, dieselbe Referenz über mehrere Ebenen zu teilen. Natürlich müssen sie dieselbe Form verwenden, dies ist jedoch bei Zellen der Tabellen-/Sammlungsansicht üblich.

Ich weiß nicht, warum es schneller wird, wenn Sie Instanzen freigeben. Vermutlich speichert es das Rendering des Schattens im Cache und kann es für andere Instanzen in der Ansicht wiederverwenden. Ich frage mich, ob das mit noch schneller geht

0
Rufus Mall