मेरे UIView पर ड्रॉप शैडो जोड़ने का सबसे अच्छा तरीका क्या है


108

मैं एक दूसरे के ऊपर लेटे हुए विचारों को एक ड्रॉप शैडो जोड़ने की कोशिश कर रहा हूं, यह दृश्य अन्य विचारों में सामग्री को देखने की अनुमति देता है, इस नस में मैं view.clipsToBoundsऑन रखना चाहता हूं ताकि जब दृश्य गिर जाए तो उनकी सामग्री क्लिप हो जाए।

ऐसा लगता है कि मेरे लिए परतों में एक बूंद छाया जोड़ना मुश्किल हो गया है क्योंकि जब मैं clipsToBoundsछाया को चालू करता हूं तो क्लिप भी बंद हो जाता है।

मैं हेरफेर करने की कोशिश कर रहा हूं view.frameऔर view.boundsफ्रेम में एक ड्रॉप शैडो जोड़ने के लिए, लेकिन सीमा को इसे घेरने के लिए पर्याप्त रूप से अनुमति देता हूं, हालांकि मुझे इसके साथ कोई भाग्य नहीं था।

यहाँ वह कोड है जिसका उपयोग मैं एक छाया जोड़ने के लिए कर रहा हूँ (यह केवल clipsToBoundsदिखाए गए अनुसार काम करता है)

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

यहाँ छाया के एक स्क्रीनशॉट को सबसे हल्के ग्रे लेयर पर लागू किया जा रहा है। उम्मीद है कि यह एक विचार देता है कि यदि मेरी सामग्री clipsToBoundsबंद है तो कैसे ओवरलैप होगी ।

छाया आवेदन।

मैं अपने साथ एक छाया कैसे जोड़ सकता हूं UIViewऔर अपनी सामग्री को क्लिप कर सकता हूं ?

संपादित करें: बस यह जोड़ना चाहता हूं कि मैंने छाया के साथ पृष्ठभूमि छवियों का उपयोग करने के साथ भी खेला है, जो अच्छी तरह से काम करता है, हालांकि मैं अभी भी इसके लिए सबसे अच्छा कोडित समाधान जानना चाहूंगा।

जवाबों:


280

इसे इस्तेमाल करे:

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;

सबसे पहले : UIBezierPathजैसा shadowPathकि महत्वपूर्ण है प्रयोग किया जाता है। यदि आप इसका उपयोग नहीं करते हैं, तो आप पहली बार में अंतर नहीं देख सकते हैं, लेकिन उत्सुक नजर डिवाइस और / या इसी तरह की घटनाओं को घुमाने जैसी घटनाओं के दौरान होने वाली एक निश्चित अंतराल का निरीक्षण करेगा। यह एक महत्वपूर्ण प्रदर्शन ट्विक है।

अपने मुद्दे के बारे में विशेष रूप से : महत्वपूर्ण पंक्ति है view.layer.masksToBounds = NO। यह दृश्य की परत के सबलेयर्स की क्लिपिंग को अक्षम कर देता है जो दृश्य की सीमा से आगे बढ़ता है।

उन लोगों के लिए जो masksToBounds(परत पर) और दृश्य की अपनी clipToBoundsसंपत्ति के बीच अंतर है: वास्तव में कोई भी नहीं है। एक पर टॉगल करने से दूसरे पर असर पड़ेगा। अमूर्तता का सिर्फ एक अलग स्तर।


स्विफ्ट 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
}

स्विफ्ट 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
}

1
धन्यवाद, मैंने आपके कोड की कोशिश की और फिर masksToBounds = NO;अपने मूल में जोड़ने की कोशिश की - दोनों प्रयासों के साथ मैंने clipsToBounds = YES;ऑन रखा - दोनों सामग्री को क्लिप करने में विफल रहे। क्या आपके उदाहरण के साथ
खुश हो सकता है की एक पेंच

1
राउंड कॉर्नर को गले लगाने के लिए ड्रॉप शैडो कैसे प्राप्त करें, इस पर विचार करने के बजाय यह मान लें कि कॉर्नर अभी भी एक वर्ग है?
जॉन एर्क

7
@ जॉन इस कोशिश UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRoundedRect:view.bounds cornerRadius:5.0];:। परीक्षण नहीं किया गया है लेकिन आपको जो परिणाम चाहिए वह उपज चाहिए।
पक्लुज़

1
मैंने सीखा है कि जब दृश्य को एनिमेट करते हैं, तो छाया चलते समय ग्रे ट्रैक छोड़ देता है। शैडोपैथ लाइनों को हटाकर इसे हल किया गया
इशहाक

1
@shoe क्योंकि किसी भी समय दृश्य का आकार बदलता है, layoutSubviews()कहा जाता है। और अगर हम shadowPathवर्तमान आकार को प्रतिबिंबित करने के लिए समायोजित करके उस स्थान पर क्षतिपूर्ति नहीं करते हैं , तो हमारे पास एक आकार बदलने वाला दृश्य होगा, लेकिन छाया अभी भी पुराना (प्रारंभिक) आकार होगा और जहां इसे नहीं दिखाना चाहिए या बाहर नहीं देखना चाहिए। ।
पुकलज

65

स्विफ्ट 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

और स्विफ्ट 3/4/5 में:

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

यदि आप AutoLayout का उपयोग कर रहे हैं, तो इस कोड को LayoutSubviews () में डालें।

SwiftUI में, यह सब बहुत आसान है:

Color.yellow  // or whatever your view
    .shadow(radius: 3)
    .frame(width: 200, height: 100)

11
ध्यान देने के लिए धन्यवादlayoutSubviews
इस्लाम Q.

1
या देखने में और भी बेहतर हैडायलेटाउट साक्षात्कार ()
मैक्स मैकलेड

1
मेक वेरिएंट पर स्विफ्ट स्ट्रक्चर इनिशियलाइज़र को प्राथमिकता दें, जैसेCGSize(width: 0, height: 0.5)
ओलिवर एटकिंसन

मैं इस कोड को लेआउटसुब्यू () में जोड़ता हूं, यह अभी भी आईबी में प्रस्तुत नहीं करता है। क्या अन्य सेटिंग्स हैं जिन्हें मुझे चुनना है?
गधा

धन्यवाद। मैं ऑटो लेआउट का उपयोग कर रहा था और मैंने अपने आप को सोचा - अच्छी तरह से .. view.boundsइतना स्पष्ट रूप से नहीं बनाया गया है कि shadowPathयह दृश्य के संदर्भ को संदर्भित नहीं कर सकता है लेकिन कुछ CGRectZeroइसके बजाय। वैसे भी, यह layoutSubviewsमेरी समस्या को हल पिछले पर डाल दिया !
devdc

13

चाल masksToBoundsआपके दृश्य की परत की संपत्ति को ठीक से परिभाषित कर रही है:

view.layer.masksToBounds = NO;

और यह काम करना चाहिए।

( स्रोत )


13

आप डिज़ाइन संपादक में इन मूल्यों को एक्सेस करने के लिए UIView के लिए एक्सटेंशन बना सकते हैं

डिज़ाइन संपादक में छाया विकल्प

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

इंटरफ़ेस बिल्डर में उस विस्तार का उल्लेख कैसे करें
अमृत ​​गुस्सा

IBInspectable इसे इंटरफेस बिल्डर में उपलब्ध कराता है
नितेश

क्या मैं इसे ऑब्जेक्टिव सी में भी हासिल कर सकता हूं?
हरीश पाठक

2
यदि आप एक वास्तविक समय पूर्वावलोकन (इंटरफ़ेस बिल्डर में) करना चाहते हैं, यहाँ आप इसके बारे में एक अच्छा लेख पा सकते हैं spin.atomicobject.com/2017/07/18/swift-interface-builder
medskill

7

आप स्टोरीबोर्ड से भी अपने दृश्य में छाया सेट कर सकते हैं

यहां छवि विवरण दर्ज करें


2

देखें

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
}

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

उपयोग:

sampleView.addDropShadowToView(sampleView)

1
बस लागू करें targetView: UIViewऔर बैंग्स को हटा दें।
ब्लूबैम्बो

6
उपयोग क्यों नहीं self? मेरे लिए बहुत अधिक सुविधाजनक लगता है।
LinusGeffarth

3
इसका एक बेहतर तरीका यह है कि targetView को एक पैरामीटर के रूप में हटा दिया जाए और targetView के बजाय स्वयं का उपयोग किया जाए। यह अतिरेक को समाप्त करता है और किसी को इसे इस तरह से कॉल करने की अनुमति देता है: sampleView.addDropShadowToView ()
23

मैक्स नेल्सन की टिप्पणी महान है। मेरा सुझाव if let!
जॉनी

0

तो हाँ, आपको प्रदर्शन के लिए शैडोपैथ प्रॉपर्टी को प्राथमिकता देनी चाहिए, लेकिन यह भी: CALayer.shadowPath की हेडर फ़ाइल से

स्पष्ट रूप से इस संपत्ति का उपयोग करते हुए पथ निर्दिष्ट करना आमतौर पर * प्रतिपादन प्रदर्शन में सुधार करेगा, जैसा कि कई परतों में समान पथ * संदर्भ साझा करेगा

एक कम ज्ञात चाल एक ही संदर्भ को कई परतों में साझा कर रही है। बेशक उन्हें एक ही आकार का उपयोग करना है, लेकिन यह तालिका / संग्रह दृश्य कोशिकाओं के साथ आम है।

मुझे नहीं पता कि अगर आप उदाहरण साझा करते हैं तो यह तेज क्यों होता है, मुझे लगता है कि यह छाया के प्रतिपादन को कैश करता है और दृश्य में अन्य उदाहरणों के लिए इसका पुन: उपयोग कर सकता है। मुझे आश्चर्य है कि अगर यह और भी तेज है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.