कैलेयर्स को इसके यूआईवीवाई के सीमा परिवर्तन पर आकार नहीं मिला। क्यों?


101

मेरे पास एक है UIViewजिसकी CALayerपरत में लगभग 8 अलग-अलग सबलेयर जोड़े गए हैं। यदि मैं दृश्य की सीमा (एनिमेटेड) को संशोधित करता हूं , तो दृश्य स्वयं सिकुड़ जाता है (मैंने इसे एक के साथ जांचा backgroundColor), लेकिन सबलेयर्स का आकार अपरिवर्तित रहता है

इसे कैसे हल करें?

जवाबों:


149

मैंने उसी दृष्टिकोण का उपयोग किया जो कि सोलिन ने उपयोग किया था, लेकिन उस कोड में एक टाइपो है। विधि होनी चाहिए:

- (void)layoutSubviews {
  [super layoutSubviews];
  // resize your layers based on the view's new bounds
  mylayer.frame = self.bounds;
}

अपने उद्देश्यों के लिए, मैं हमेशा चाहता था कि सबलेयर पैरेंट दृश्य का पूर्ण आकार हो। उस विधि को अपने दृश्य वर्ग में रखें।


8
@fishinear क्या आपको यकीन है? ऐसा लगता है कि आप फ्रेम का वर्णन कर रहे हैं। सीमा, सैद्धांतिक रूप से, हमेशा इसकी उत्पत्ति के रूप में 0,0 होनी चाहिए।
grispeak

3
@griotspeak - वास्तव में ऐसा नहीं है। बाउंड्स प्रॉपर्टी का विवरण यहां देखें: developer.apple.com/library/ios/#documentation/uikit/reference/… - "डिफ़ॉल्ट रूप से, सीमा आयत का मूल (0, 0) पर सेट है, लेकिन आप कर सकते हैं दृश्य के विभिन्न भागों को प्रदर्शित करने के लिए इस मान को बदलें। "
jdc

बहुत धन्यवाद, मैंने कुछ मामलों के बारे में सीखा है (स्क्रॉल दृश्य, एक के लिए) जहां यह सच नहीं है लेकिन मैं इस टिप्पणी के बारे में भूल गया।
ग्रिटस्पेक

31
कॉल करने के लिए मत भूलना [सुपर लेआउटसुबह], क्योंकि यह विभिन्न UIKit कक्षाओं में अप्रत्याशित व्यवहार का कारण बन सकता है।
Kpmurphy91

2
यह मेरे लिए एक आत्म-आकार UITextView(स्क्रॉलअन = NO) और ऑटो लेआउट के साथ बहुत अच्छी तरह से काम नहीं करता था । मेरे पास एक टेक्स्ट व्यू था, जो इसके सुपरवाइज के लिए पिन किया हुआ था, जिसके बदले CALayerमें खुद (नीचे एक बॉर्डर) था, और मैं चाहता था कि जब टेक्स्ट व्यू की हाइट बदल जाए, तो बॉर्डर पोजिशन को अपडेट कर सके। किसी कारण layoutSubiewsसे बहुत देर से रास्ता कहा गया था (और परत की स्थिति एनिमेटेड थी)।
Iosdude

26

चूंकि iPhone पर CALayer लेआउट प्रबंधकों का समर्थन नहीं करता है, मुझे लगता है कि आपको अपने दृश्य की मुख्य परत को एक कस्टम CALayer उपवर्ग बनाना होगा, जिसमें आप layoutSublayersसभी सबलेयर्स के फ़्रेम सेट करने के लिए ओवरराइड करते हैं। आपको +layerClassअपने नए CALayer उपवर्ग के वर्ग को वापस करने के लिए अपने दृश्य की विधि को भी ओवरराइड करना होगा ।


ओपनर लेयर ओवरराइड के मामले में ओवरराइड + लेयरक्लास पसंद है? ऐसा सोचता। सबलेयर के फ्रेम सेट करें? क्या सेट करें? मुझे सभी सबलेयर्स फ्रेम / पदों की गणना सुपरलेयर फ्रेम आकार के आधार पर व्यक्तिगत रूप से करनी है? क्या कोई "अड़चन जैसा" या "लिंक-टू-सुपरलेयर" जैसा समाधान नहीं है? ओह, भगवान, टाइम-फ्रेम से बाहर एक और दिन। CGLayers का आकार बदला गया, लेकिन बहुत ही सुस्त था, CALayers काफी तेज़ हैं, लेकिन उनका आकार बदला नहीं गया। इतने सारे आश्चर्य। वैसे भी, उत्तर के लिए धन्यवाद।
गेरी बोरबास

3
मैक पर कैलेयर के पास इसके लिए लेआउट प्रबंधक हैं लेकिन वे iPhone पर उपलब्ध नहीं हैं। तो हाँ, आपको फ्रेम के आकार की गणना स्वयं करनी होगी। एक और विकल्प सबलेयर्स के बजाय सबव्यू का उपयोग कर सकता है। फिर आप अपने हिसाब से सबवॉइस मास्क सेट कर सकते हैं।
ओले Begemann

2
हां, यूआईवीवाई बहुत ही महंगी क्लास हैं, इसके बाद मैं कैलियर्स का इस्तेमाल करती हूं।
गेरी बोरबास

मैंने आपके द्वारा सुझाए गए तरीके को आजमाया। यह काम करता है, और यह नहीं है। मैं दृश्य को एनिमेटेड आकार देता हूं, लेकिन सबलेयर्स एक अलग एनीमेशन में आकार बदलता है। खूनी नरक, अब क्या करना है? दृश्य के एनीमेशन के EVERY (!) फ़्रेम पर क्या आह्वान किया गया है, जो कैलेयर उपवर्ग में ओवरराइड करने की विधि है? क्या वहाँ कोई?
गेरी बोरबास

बस इस में भी टकरा गया। ऐसा लगता है कि ऑल ने कहा कि कैलेयर को उप-वर्ग में रखना सबसे अच्छा विकल्प है, लेकिन यह अनावश्यक रूप से बोझिल लगता है।
दिमित्री

15

मैंने इसका उपयोग UIView में किया।

-(void)layoutSublayersOfLayer:(CALayer *)layer
{
    if (layer == self.layer)
    {
        _anySubLayer.frame = layer.bounds;
    }

super.layoutSublayersOfLayer(layer)
}

मेरे लिये कार्य करता है।


हां, यह मेरे लिए iOS 8 में काम करता है। संभवतः पहले के संस्करणों में काम करेगा। मेरे पास एक ढाल पृष्ठभूमि परत थी और डिवाइस को घुमाए जाने पर परत को आकार देने की आवश्यकता थी।
ईपीज_एड

मेरे लिए काम किया है, लेकिन यह
एन्ट्रापी

यह सबसे अच्छा जवाब है! हाँ, मैंने लेआउट की कोशिश की है साक्षात्कार लेकिन यह केवल मेरे UITextField के लेआउट को तोड़ता है जैसे बायां दृश्य और दायाँ गायब होना और UITextField में अधिक पाठ गायब होना। हो सकता है कि मैंने UIView की विरासत के बजाय एक्सटेंशन का उपयोग किया हो, लेकिन यह बहुत छोटी गाड़ी थी। इस महान काम करता है! THX
मिचेल जिब्रो

कस्टम ड्राइंग ( CALayerDelegateएस draw(_:in:)) के साथ एक परत के लिए , मुझे कॉल भी करना था _anySubLayer.setNeedsDisplay()। फिर यह मेरे लिए काम किया।
jedwidz

9

मुझे भी यही समस्या थी। एक कस्टम दृश्य की परत में मैंने दो और सबलेयर जोड़े। सबलेयर्स (हर बार कस्टम दृश्य की सीमाओं को बदलने) का आकार बदलने के लिए, मैंने layoutSubviewsअपने कस्टम दृश्य की विधि को लागू किया ; इस पद्धति के अंदर मैं अपने उप-परत की वर्तमान सीमाओं से मेल खाने के लिए प्रत्येक उप-परत के फ्रेम को अपडेट करता हूं।

कुछ इस तरह:

-(void)layoutSubviews{
   //keep the same origin, just update the width and height
   if(sublayer1!=nil){
      sublayer1.frame = self.layer.bounds;
   }
}

16
FYI करें, अगर आपको (sublayer1! = Nil) जरूरत नहीं है, क्योंकि ObjC nil को संदेश परिभाषित करता है (इस मामले में, -Frame :) एक no-op के रूप में वापस लौट रहा है
एंड्रयू Pouliot

7

2017

इस प्रश्न का शाब्दिक उत्तर:

"कैलेयर्स को इसके यूआईवीवाई की सीमा परिवर्तन पर आकार नहीं मिला। क्यों?"

यह बेहतर या बदतर के लिए है

needsDisplayOnBoundsChange

झूठे में चूक CALayer

उपाय,

class CircularGradientViewLayer: CALayer {
    
    override init() {
        
        super.init()
        needsDisplayOnBoundsChange = true
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override open func draw(in ctx: CGContext) {
        go crazy drawing in .bounds
    }
}

दरअसल, मैं आपको इस QA के लिए निर्देशित करता हूं

https://stackoverflow.com/a/47760444/294884

जो बताता है, जो महत्वपूर्ण contentsScaleसेटिंग करता है; आपको आमतौर पर समान रूप से सेट करने की आवश्यकता होती है कि आप कब सेट करते हैं। डिसप्लेऑनबाउंडसचेंज।


5

स्विफ्ट 3 संस्करण

कस्टम सेल में, निम्न पंक्तियाँ जोड़ें

पहले घोषणा करें

let gradientLayer: CAGradientLayer = CAGradientLayer()

फिर निम्नलिखित पंक्तियों को जोड़ें

override func layoutSubviews() {
    gradientLayer.frame = self.YourCustomView.bounds
}

0

जैसा कि [ओले] ने लिखा है कि काइलर आईओएस पर ऑटोरेस्ज़िंग का समर्थन नहीं करता है। इसलिए आपको मैन्युअल रूप से लेआउट को समायोजित करना चाहिए। मेरा विकल्प परत के फ्रेम को (आईओएस 7 और पूर्व में) समायोजित करना था

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 

या (आईओएस 8 के रूप में)

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinato

0

आपके कस्टम दृश्य में, आपको अपनी कस्टम लेयर के लिए वैरिएबल डिक्लेयर करना होगा, स्कोप को init में वैरिएबल डिक्लेयर नहीं करना चाहिए। और बस इसे एक बार init करें, सेट करने की कोशिश मत करो अशक्त मूल्य और प्रबलित

    वर्ग कस्टम दृश्य: UIView {
        var customLayer: CALayer = CALayer ()

        ओवरव्यू फंक लेआउटसुभाष () {
            super.layoutSubviews ()
    // गार्ड को _fillColor = self._fillColor वरना {वापसी}
            initializeLayout ()
        }
        निजी दुर्गंध initializeLayout () { 
            customLayer.removeFromSuperView ()
            customLayer.frame = परत। सीमाएँ
                   
            layer.insertSubview (कम: 0)
        }
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.