ऑटो लेआउट के साथ UICollectionView स्व नौकरशाही का आकार घटाने सेल


207

मैं UICollectionViewCellsऑटो लेआउट के साथ काम करने के लिए आत्म-आकार देने की कोशिश कर रहा हूं , लेकिन मैं सामग्री को आकार देने के लिए कोशिकाओं को प्राप्त नहीं कर सकता। मुझे यह समझने में परेशानी हो रही है कि सेल के सामग्री दृश्य के अंदर सेल के आकार को कैसे अपडेट किया गया है।

यहां मैंने जो सेटअप आज़माया है:

  • इसके contentView में कस्टम के UICollectionViewCellसाथ UITextView
  • के लिए स्क्रॉल UITextViewकरना अक्षम है।
  • ContentView का क्षैतिज अवरोध है: "H: | [_textView (320)]", अर्थात इसे UITextView320 की स्पष्ट चौड़ाई के साथ सेल के बाईं ओर पिन किया गया है।
  • ContentView का लंबवत अवरोध है: "V: -0 -0 - [_ textView]", यानी UITextViewसेल के शीर्ष पर पिन किया गया।
  • UITextViewएक ऊंचाई बाधा एक निरंतर जो करने के लिए सेट है UITextViewरिपोर्ट पाठ फिट होगा।

यहां सेल बैक के साथ सेट की गई लाल रंग की UITextViewपृष्ठभूमि और ब्लू के लिए सेट की पृष्ठभूमि के साथ ऐसा दिखता है : सेल पृष्ठभूमि लाल, UITextView पृष्ठभूमि नीला

मैंने उस परियोजना को रखा है जिसे मैं यहां GitHub के साथ खेल रहा हूं ।


क्या आप sizeForItemAtIndexPath पद्धति लागू कर रहे हैं?
डैनियल गैलास्को

@DanielGalasko मैं नहीं हूँ। मेरी समझ यह है कि iOS 8 में नए सेल्फ साइज़िंग सेल फ़ीचर आपको ऐसा करने की आवश्यकता नहीं है।
कच्ची

निश्चित नहीं है कि आपको वह जानकारी कहां से मिली है, लेकिन फिर भी आपको डब्ल्यूडब्ल्यूडीसी के अंश asciiwwdc.com/2014/session/226
डैनियल गैलास्को

लेकिन फिर से यह आपके उपयोग के मामले पर निर्भर करता है, सुनिश्चित करें कि आप अनुमान लागू करते हैं
डैनियल गैलास्को

1
2019 - इस पर ध्यान देना आवश्यक है: stackoverflow.com/a/58108897/294884
Fattie

जवाबों:


309

स्विफ्ट 5 के लिए अपडेट किया गया

preferredLayoutAttributesFittingAttributespreferredLayoutAttributesFittingऑटो साइज़िंग का नाम और उपयोग


स्विफ्ट 4 के लिए अपडेट किया गया

systemLayoutSizeFittingSize का नाम बदल दिया systemLayoutSizeFitting


IOS 9 के लिए अपडेट किया गया

IOS 9 के तहत मेरे GitHub समाधान को देखने के बाद मुझे आखिरकार इस मुद्दे की पूरी तरह से जांच करने का समय मिला। मैंने अब स्व-आकार देने वाली कोशिकाओं के लिए विभिन्न कॉन्फ़िगरेशन के कई उदाहरणों को शामिल करने के लिए रेपो को अपडेट किया है। मेरा निष्कर्ष यह है कि स्व-आकार देने वाले सेल सिद्धांत में महान हैं लेकिन व्यवहार में गड़बड़ हैं। स्व-आकार देने वाली कोशिकाओं के साथ आगे बढ़ने पर सावधानी का एक शब्द।

टी एल; डॉ

मेरे GitHub प्रोजेक्ट को देखें


सेल्फ साइजिंग सेल केवल फ्लो लेआउट के साथ समर्थित हैं, इसलिए सुनिश्चित करें कि आप क्या उपयोग कर रहे हैं।

काम करने के लिए स्व-आकार देने वाली कोशिकाओं के लिए सेटअप करने के लिए आपको दो चीजें चाहिए।

1. सेट estimatedItemSizeपरUICollectionViewFlowLayout

estimatedItemSizeप्रॉपर्टी सेट करते ही फ्लो लेआउट प्रकृति में गतिशील हो जाएगा ।

self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

2. अपने सेल उपवर्ग पर आकार देने के लिए समर्थन जोड़ें

यह 2 स्वादों में आता है; ऑटो-लेआउट या कस्टम ओवरराइड preferredLayoutAttributesFittingAttributes

ऑटो लेआउट के साथ सेल बनाएं और कॉन्फ़िगर करें

मैं इसके बारे में विस्तार से नहीं बताऊंगा क्योंकि एक सेल के लिए बाधाओं को कॉन्फ़िगर करने के बारे में एक शानदार एसओ पोस्ट है । बस इस बात से सावधान रहें कि Xcode 6 ने iOS 7 के साथ सामान का एक गुच्छा तोड़ दिया है, इसलिए यदि आप iOS 7 का समर्थन करते हैं, तो आपको ऐसे सामान करने की आवश्यकता होगी जैसे यह सुनिश्चित करें कि ऑटोरेस्पोन्गिंग मास्क सेल के contentView पर सेट है और जब सामग्री की सीमा सेल की सीमा के रूप में सेट होती है। सेल लोड किया गया है (यानी awakeFromNib)।

जिन चीजों की आपको जानकारी होनी चाहिए, वह यह है कि आपके सेल को टेबल व्यू सेल की तुलना में अधिक गंभीरता से विवश होना चाहिए। उदाहरण के लिए, यदि आप चाहते हैं कि आपकी चौड़ाई गतिशील हो तो आपके सेल को ऊंचाई में अवरोध की आवश्यकता होती है। इसी तरह, यदि आप चाहते हैं कि ऊँचाई गतिशील हो तो आपको अपने सेल में एक चौड़ाई की कमी की आवश्यकता होगी।

preferredLayoutAttributesFittingAttributesअपने कस्टम सेल में लागू करें

जब यह फ़ंक्शन कहलाता है तो आपका दृश्य पहले से ही सामग्री के साथ कॉन्फ़िगर किया गया है (जैसे cellForItemकहा जाता है)। अपने अवरोधों को उचित रूप से निर्धारित करते हुए कि आप इस तरह एक कार्यान्वयन हो सकता है:

//forces the system to do one layout pass
var isHeightCalculated: Bool = false

override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
    //Exhibit A - We need to cache our calculation to prevent a crash.
    if !isHeightCalculated {
        setNeedsLayout()
        layoutIfNeeded()
        let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
        var newFrame = layoutAttributes.frame
        newFrame.size.width = CGFloat(ceilf(Float(size.width)))
        layoutAttributes.frame = newFrame
        isHeightCalculated = true
    }
    return layoutAttributes
}

नोट iOS 9 पर व्यवहार थोड़ा बदल गया है जो आपके कार्यान्वयन पर क्रैश का कारण बन सकता है यदि आप सावधान नहीं हैं ( यहाँ और देखें )। जब आप लागू preferredLayoutAttributesFittingAttributesकरते हैं तो आपको यह सुनिश्चित करने की आवश्यकता होती है कि आप केवल एक बार अपने लेआउट विशेषताओं के फ्रेम को बदल दें। यदि आप ऐसा नहीं करते हैं तो लेआउट अनिश्चित रूप से आपके कार्यान्वयन को कॉल करेगा और अंततः दुर्घटनाग्रस्त हो जाएगा। एक उपाय यह है कि आप अपने सेल में परिकलित आकार को कैश करें और इसे तब तक अमान्य कर दें जब तक आप सेल का पुनः उपयोग न करें या इसकी सामग्री को बदल दें जैसा कि मैंने इसके साथ किया हैisHeightCalculated संपत्ति के है।

अपने लेआउट का अनुभव करें

इस बिंदु पर आपको अपने संग्रह दृश्य में 'कार्यशील' डायनामिक सेल होना चाहिए। मुझे अभी तक मेरे परीक्षणों के दौरान आउट-ऑफ-द-बॉक्स समाधान पर्याप्त नहीं मिला है इसलिए यदि आपके पास है तो टिप्पणी करने के लिए स्वतंत्र महसूस करें। यह अभी भी महसूस करता है कि UITableViewगतिशील नौकरशाही का आकार घटाने के लिए लड़ाई जीतता है।

चेतावनियां

बहुत ध्यान रखें कि यदि आप अनुमान लगाने के लिए प्रोटोटाइप कोशिकाओं का उपयोग कर रहे हैं, तो यह अनुमान लगाता है कि यदि आपका XIB आकार की कक्षाओं का उपयोग करता है, तो यह टूट जाएगा । इसका कारण यह है कि जब आप अपने सेल को एक XIB से लोड करते हैं तो इसका आकार वर्ग के साथ कॉन्फ़िगर किया जाएगा Undefined। यह केवल iOS 8 और ऊपर से टूट जाएगा iOS 7 पर आकार वर्ग डिवाइस (iPad = Regular-Any, iPhone = Compact-Any) के आधार पर लोड किया जाएगा। आप XIB को लोड किए बिना अनुमानित या तो सेट कर सकते हैं, या आप XIB से सेल को लोड कर सकते हैं, इसे संग्रह दृश्य में जोड़ सकते हैं (यह traitCollection सेट कर देगा), लेआउट निष्पादित करें, और फिर इसे पर्यवेक्षण से हटा दें। वैकल्पिक रूप से आप अपने सेल को traitCollectionगेटटर को ओवरराइड कर सकते हैं और उचित लक्षण वापस कर सकते हैं। यह आप पर निर्भर करता है।

मुझे बताएं कि क्या मुझे कुछ याद आया है, आशा है कि मैंने मदद की और सौभाग्य कोडिंग



2
मैं प्रवाह लेआउट के साथ एक ही बात को लागू करने की कोशिश कर रहा हूं, हालांकि जब मैं इसे नए आकार में अद्यतन आकार के साथ वापस करता हूं, तो लेआउट y पदों को पुनर्गणना नहीं करता है, जो अभी भी अनुमानित आकार में ऊंचाई पर आधारित हैं। क्या कमी है?
अन्न्या

@ आप लेआउट पर अमान्य कॉल कर रहे हैं?
डैनियल गैलास्को

1
आह, अंतर पाया, आपने अनुमानित ऊंचाई बहुत अधिक (400) निर्धारित की, जबकि मैं न्यूनतम (44) कर रहा था। इससे मदद मिली। लेकिन सामग्री को अभी भी सही ढंग से सेट नहीं किया जा रहा है जब तक कि आप उस तरह से सभी को स्क्रॉल नहीं करते हैं, इसलिए अभी भी बहुत उपयोगी नहीं है। Btw, मैंने UITextView को UILabel में बदल दिया, समान व्यवहार।
अन्नू

17
यह iOS 9 GM पर मूलभूत रूप से टूटा हुआ प्रतीत होता है। सेटिंग estimatedItemSizeक्रैश की ओर ले जाती है - कुछ विशाल बग लगता है कि कैसे ऑटो लेआउट UICollectionViewCell को संसाधित करने की कोशिश कर रहा है।
वेस कैंपेन

3
एक समान मुद्दे में चल रहा है, किसी को भी चारों ओर एक काम मिल गया है?
टोनी

47

IOS10 में नया स्थिरांक UICollectionViewFlowLayout.automaticSize(पूर्व में UICollectionViewFlowLayoutAutomaticSize) कहा जाता है , इसलिए इसके बजाय:

self.flowLayout.estimatedItemSize = CGSize(width: 100, height: 100)

आप इसका उपयोग कर सकते हैं:

self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

इसका बेहतर प्रदर्शन है, खासकर जब आपके पास संग्रह दृश्य में कोशिकाएं लगातार व्यापक होती हैं

एक्सेस फ़्लो लेआउट:

override func viewDidLoad() {
   super.viewDidLoad()

   if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
      flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
   }
}

स्विफ्ट 5 अपडेटेड:

override func viewDidLoad() {
   super.viewDidLoad()

   if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
      flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
    }
}

8
आप इसे कहां सेट करते हैं? देखने में आपको फ्लोयलेआउट पर एक हैंडल कैसे मिलता है?
UKDataGeek

1
मैं इसे लागू करने में कामयाब रहा - लेकिन इसका एक अजीब व्यवहार है जो इसे एकल कोशिका होने पर कोशिकाओं को केंद्र बनाता है। यहाँ इसके बारे में स्टैक ओवरफ्लो प्रश्न है - मुझे स्टम्प किया गया है: stackoverflow.com/questions/43266924/…
UKDataGeek

1
आप संग्रह collectionViewLayoutUICollectionViewFlowLayout
दृश्य के

4
यह मेरी कोशिकाओं को बहुत छोटा बनाता है, बेकार है
user924

44

डैनियल गैलास्को के जवाब में कुछ महत्वपूर्ण बदलावों ने मेरी सभी समस्याओं को ठीक कर दिया। दुर्भाग्य से, मेरे पास सीधे (अभी तक) टिप्पणी करने के लिए पर्याप्त प्रतिष्ठा नहीं है।

चरण 1 में, ऑटो लेआउट का उपयोग करते समय, बस सेल में एक एकल अभिभावक UIView जोड़ें। सेल के अंदर सब कुछ माता-पिता का एक उपक्षेत्र होना चाहिए। मेरी सभी समस्याओं का जवाब दिया। हालांकि Xcode इसे UITableViewCells के लिए स्वचालित रूप से जोड़ता है, यह UICollectionViewCells के लिए (लेकिन यह नहीं होना चाहिए)। डॉक्स के अनुसार :

अपने सेल की उपस्थिति को कॉन्फ़िगर करने के लिए, सामग्री दृश्य में संपत्ति के दृश्य के रूप में डेटा आइटम की सामग्री को प्रस्तुत करने के लिए आवश्यक विचार जोड़ें। सीधे ही सेल में साक्षात्कार न जोड़ें।

फिर चरण 3 को पूरी तरह से छोड़ दें। इसकी जरूरत नहीं है।


1
दिलचस्प; यह विशेष रूप से Xibs के लिए है, लेकिन फिर भी धन्यवाद, Github परियोजना के साथ प्रयास करना होगा और देखना होगा कि क्या मैं पुन: पेश कर सकता हूं। शायद
Xib

बहुत मददगार । धन्यवाद!
प्रॉब्लमस्लोवर

2
iOS 9, Xcode 7. स्टोरीबोर्ड में सेल प्रोटॉप्ड किए गए हैं, कस्टम उपवर्ग सेट करें। नामक एक संपत्ति बनाने की कोशिश की contentView, Xcode शिकायत करता है कि यह मौजूदा संपत्ति के साथ संघर्ष करता है। self.contentViewउस पर विवश करने के लिए साक्षात्कार जोड़ने की कोशिश की , फिर ऐप क्रैश हो गया।
निकोलस मियारी

@NicolasMiari मुझे इस बारे में नहीं पता है कि इस कार्यक्रम को कैसे करना है, मेरा समाधान वास्तव में XIB में एक एकल uiview जोड़ने के लिए है जहां सब कुछ इसके अंदर जाता है। आपको संपत्ति या कुछ भी बनाने की आवश्यकता नहीं है।
मैट कोआला

मैं @NicolasMiari जैसी ही समस्या का सामना कर रहा हूं। जब मैंने अनुमान लगाया कि आईओएस 9 / एक्सकोड 7 पर ऑटोलेयूट बाधाओं के साथ स्टोरीबोर्ड में कोशिकाओं के लिए प्रोटोटाइप किए गए सेल के लिए एप्लिकेशन खराब पहुंच अपवाद और कोई सहायक स्टैकट्रेस के साथ क्रैश होता है
वसाबी

34

IOS 10+ में यह एक बहुत ही सरल 2 चरण प्रक्रिया है।

  1. सुनिश्चित करें कि आपकी सभी सेल सामग्री एक एकल यूआईईवीवाई (या यूआईएसवाईवाई के एक वंशज जैसे यूआईएसटैक्यूव के अंदर रखी गई है जो ऑटोलॉययट को सरल बनाता है)। UITableViewCells को गतिशील रूप से आकार देने के साथ की तरह, पूरे दृश्य पदानुक्रम को सबसे बाहरी कंटेनर से अंतरतम दृश्य तक, कॉन्फ़िगर होने की आवश्यकता है। इसमें UICollectionViewCell और तत्काल चाइल्डव्यू के बीच बाधाएं शामिल हैं

  2. स्वचालित रूप से आकार देने के लिए अपने UICollectionView के flowlayout को निर्देश दें

    yourFlowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

Im जिज्ञासु, कैसे एक UIView में अपने सेल सामग्री लपेटकर ऑटो लेआउट बेहतर प्रदर्शन करेंगे? Id ने सोचा है कि यह अधिक उथले पदानुक्रम के साथ बेहतर प्रदर्शन करेगा?
जेम्स हेडल

1
मैंने प्रदर्शन का उल्लेख नहीं किया, केवल सादगी। स्व-आकार देने वाली कोशिकाएं केवल तभी काम करेंगी जब आपके पास बाएं और दाएं के बीच और ऊपर और नीचे के बीच सभी तरह की बाधाएं हों। यह प्राप्त करना सबसे आसान है जब सभी दृश्य एक ही कंटेनर में लिपटे हों। यदि वह कंटेनर UIStackView है तो यह आसान है कि यदि वह UIView का कोई अन्य वंशज है।
मरमॉय

क्या आप मुझे बता सकते हैं कि UICollectionViewViewFlowLayoutAutomaticSize के लिए ऊंचाई स्थिर कैसे सेट करें (जैसे सेट ऊँचाई 25, और चौड़ाई स्वचालित रूप से बदल जाएगी)।
स्वेतोस्लाव अटानासोव

स्विफ्ट 4.1 का उपयोग करते हुए, Xcode बताता है कि मेरा UICollectionViewFlowLayout.automaticSizeनाम बदल दिया गया है UICollectionViewFlowLayoutAutomaticSize
लिनसग्राफ 17

14
  1. FlowDayout दृश्य पर जोड़ें ()

    override func viewDidLoad() {
        super.viewDidLoad() 
        if let flowLayout = infoCollection.collectionViewLayout as? UICollectionViewFlowLayout {
            flowLayout.estimatedItemSize = CGSize(width: 1, height:1)
        }
    }
  2. इसके अलावा, अपने सेल के लिए मेनकॉर्नर के रूप में एक यूआईवीयूवाई सेट करें और इसके अंदर सभी आवश्यक विचार जोड़ें।

  3. आगे के संदर्भ के लिए इस भयानक, मन उड़ाने वाले ट्यूटोरियल का संदर्भ लें: iOS 9 और 10 में ऑटोलेयूट का उपयोग करके ऑटोसाइज़िंग सेल के साथ UICollectionView


11

EDIT 11/19/19: iOS 13 के लिए, अनुमानित ऊंचाई के साथ UICollectionViewCompositionalLayout का उपयोग करें। इस टूटे हुए एपीआई से निपटने में अपना समय बर्बाद न करें।

कुछ समय तक इससे जूझने के बाद, मैंने देखा कि यदि आप स्क्रॉलिंग को अक्षम नहीं करते हैं, तो आकार बदलना UITextViews के लिए काम नहीं करता है:

let textView = UITextView()
textView.scrollEnabled = false

जब मैं स्क्रॉल करने का प्रयास करता हूं, तो संग्रह दृश्य कक्ष सुचारू नहीं होता है। क्या आपके पास इसके लिए कोई उपाय है?
सतीश कुमार गुरुनाथन

6

contentView लंगर रहस्य:

एक विचित्र मामले में यह

    contentView.translatesAutoresizingMaskIntoConstraints = false

काम नहीं करेगा। कंटेंट व्यू में चार स्पष्ट एंकर जोड़े और यह काम किया।

class AnnoyingCell: UICollectionViewCell {
    
    @IBOutlet var word: UILabel!
    
    override init(frame: CGRect) {
        super.init(frame: frame); common() }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder); common() }
    
    private func common() {
        contentView.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            contentView.leftAnchor.constraint(equalTo: leftAnchor),
            contentView.rightAnchor.constraint(equalTo: rightAnchor),
            contentView.topAnchor.constraint(equalTo: topAnchor),
            contentView.bottomAnchor.constraint(equalTo: bottomAnchor)
        ])
    }
}

और हमेशा की तरह

    estimatedItemSize = UICollectionViewFlowLayout.automaticSize

में YourLayout: UICollectionViewFlowLayout

कौन जानता है? किसी की मदद कर सकते हैं।

श्रेय

https://www.vadimbulavin.com/collection-view-cells-self-sizing/

वहाँ की नोक पर ठोकर खाई - कभी भी इसे इस पर सभी विभिन्न लेखों में कहीं और नहीं देखा।


3

मैंने संग्रह दृश्य की एक गतिशील सेल ऊंचाई की। यहाँ git hub repo है

और, खोदो क्यों पसंद करते हैं। दरअसल, इसे कम से कम 3 बार कहा जाएगा।

कंसोल लॉग तस्वीर: यहां छवि विवरण दर्ज करें

1 preferredLayoutAttributesFittingAttributes :

(lldb) po layoutAttributes
<UICollectionViewLayoutAttributes: 0x7fa405c290e0> index path: (<NSIndexPath:    0xc000000000000016> 
{length = 2, path = 0 - 0}); frame = (15 12; 384 57.5); 

(lldb) po self.collectionView
<UICollectionView: 0x7fa40606c800; frame = (0 57.6667; 384 0);

यह लेआउट वर्तमान स्थिति 57.5 है

2 पसंद लाइएआउटआउट :

(lldb) po layoutAttributes
<UICollectionViewLayoutAttributes: 0x7fa405c16370> index path: (<NSIndexPath: 0xc000000000000016> 
{length = 2, path = 0 - 0}); frame = (15 12; 384 534.5); 

(lldb) po self.collectionView
<UICollectionView: 0x7fa40606c800; frame = (0 57.6667; 384 0);

सेल फ्रेम ऊँचाई में बदल गया हमारी उम्मीद के अनुसार 534.5 हो गई। लेकिन, संग्रह दृश्य अभी भी शून्य ऊंचाई है।

3 पसंदीदालीटएट्यूएंटेजफिटिंग एट्रिब्यूट्स :

(lldb) po layoutAttributes
<UICollectionViewLayoutAttributes: 0x7fa403d516a0> index path: (<NSIndexPath: 0xc000000000000016> 
{length = 2, path = 0 - 0}); frame = (15 12; 384 534.5); 

(lldb) po self.collectionView
<UICollectionView: 0x7fa40606c800; frame = (0 57.6667; 384 477);

आप देख सकते हैं संग्रह दृश्य ऊंचाई 0 से 477 तक बदल दी गई थी

व्यवहार स्क्रॉल को संभालने के समान है:

1. Before self-sizing cell

2. Validated self-sizing cell again after other cells recalculated.

3. Did changed self-sizing cell

शुरुआत में, मुझे लगा कि यह तरीका केवल एक बार ही कॉल करेगा। तो मैं निम्नलिखित के रूप में कोडित हूं:

CGRect frame = layoutAttributes.frame;
frame.size.height = frame.size.height + self.collectionView.contentSize.height;
UICollectionViewLayoutAttributes* newAttributes = [layoutAttributes copy];
newAttributes.frame = frame;
return newAttributes;

यह रेखा:

frame.size.height = frame.size.height + self.collectionView.contentSize.height;

सिस्टम कॉल का कारण अनंत लूप और ऐप क्रैश होगा।

किसी भी आकार को बदल दिया गया है, यह सभी कोशिकाओं की पसंद को सत्यापित करेगा।


2

उपरोक्त उत्तरों के अलावा,

बस सुनिश्चित करें कि आपने अनुमानित सेट किया है। UICollectionViewFlowLayout की संपत्ति को कुछ आकार में सेट करें और आकार लागू न करें। यह काम करें: atIndexPath प्रतिनिधि विधि।

बस।


1

यदि आप UICollectionViewDelegateFlowLayout विधि लागू करते हैं:

- (CGSize)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath*)indexPath

जब आप कॉल करते हैं collectionview performBatchUpdates:completion:, तो आकार की ऊँचाई का उपयोग sizeForItemAtIndexPathइसके बजाय होगाpreferredLayoutAttributesFittingAttributes

की रेंडरिंग प्रक्रिया performBatchUpdates:completionविधि से preferredLayoutAttributesFittingAttributesगुजरेगी लेकिन यह आपके परिवर्तनों को नजरअंदाज करती है।


मैंने यह दुर्व्यवहार देखा है, लेकिन केवल तब जब अनुमानित आकार शून्य हो। क्या आप वाकई एक अनुमानित आकार सेट कर रहे हैं?
dgatwood

1

यह किसकी मदद कर सकता है,

अगर estimatedItemSizeसेट किया गया था कि मैं बुरा दुर्घटना था। भले ही मैं 0 में वापस आ गया numberOfItemsInSection। इसलिए, स्वयं कोशिकाएं और उनके ऑटो-लेआउट दुर्घटना का कारण नहीं थे ... संग्रह दृश्य दुर्घटनाग्रस्त हो गया, यहां तक ​​कि खाली होने पर, सिर्फ इसलिएestimatedItemSize कि स्व-आकार देने के लिए सेट किया गया था।

मेरे मामले में मैंने अपनी परियोजना को पुनर्गठित किया, एक नियंत्रक से एक संग्रह दृश्य से एक संग्रह दृश्य नियंत्रक तक, और यह काम किया।

जाओ पता लगाओ।


1
के collectionView.collectionViewLayout.invalidateLayout()बाद कॉल करने का प्रयास करें collectionView.reloadData()
चेंगसम

ios10 के लिए और नीचे इस कोड को `ओवरराइड समारोह viewWillLayoutSubviews () जोड़ने {super.viewWillLayoutSubviews अगर #available () (आईओएस 11.0, *) {} else {mainCollectionView.collectionViewLayout.invalidateLayout ()}}`
Marosdee उमा

1

किसी के लिए जो बिना भाग्य के सब कुछ करने की कोशिश करता है, केवल यही एक चीज है जो इसे मेरे लिए काम कर रही है। सेल के अंदर मल्टीलाइन लेबल के लिए, इस मैजिक लाइन को जोड़ने का प्रयास करें:

label.preferredMaxLayoutWidth = 200

अधिक जानकारी: यहाँ

चीयर्स!


0

ऊपर उदाहरण विधि संकलित नहीं करता है। यहाँ एक सही संस्करण है (लेकिन यह काम करता है या नहीं इसके बारे में पता नहीं है)

override func preferredLayoutAttributesFittingAttributes(layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes 
{
    let attr: UICollectionViewLayoutAttributes = layoutAttributes.copy() as! UICollectionViewLayoutAttributes

    var newFrame = attr.frame
    self.frame = newFrame

    self.setNeedsLayout()
    self.layoutIfNeeded()

    let desiredHeight: CGFloat = self.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
    newFrame.size.height = desiredHeight
    attr.frame = newFrame
    return attr
}

0

अधिक जानकारी अपडेट करें:

  • यदि आप उपयोग करते हैं flowLayout.estimatedItemSize, तो सुझाव दें कि iOS8.3 बाद के संस्करण का उपयोग करें। IOS8.3 से पहले, यह दुर्घटनाग्रस्त हो जाएगा [super layoutAttributesForElementsInRect:rect];। त्रुटि संदेश है

    *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'

  • दूसरा, iOS8.x वर्जन में, flowLayout.estimatedItemSizeअलग-अलग सेक्शन के कारण इनसेट सेटिंग काम नहीं करेगी। समारोह (UIEdgeInsets)collectionView:layout:insetForSectionAtIndex::।


0

समाधान में 4 महत्वपूर्ण चरण शामिल हैं:

  1. डायनामिक सेल साइज़िंग सक्षम करना

flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

  1. स्पष्ट रूप से ऑटो लेआउट को सक्षम करें और contentViewसेल के किनारों पर पिन करें क्योंकि contentViewस्व-आकार को रोकता है, यह देखते हुए कि इसमें ऑटो लेआउट सक्षम नहीं है।
class MultiLineCell: UICollectionViewCell{

    private var textViewHeightContraint: NSLayoutConstraint!

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .cyan
        contentView.translatesAutoresizingMaskIntoConstraints = false
        contentViewWidthAnchor = contentView.widthAnchor.constraint(equalToConstant: 0)

        NSLayoutConstraint.activate([
            contentView.leadingAnchor.constraint(equalTo: leadingAnchor),
            contentView.topAnchor.constraint(equalTo: topAnchor),
            contentView.trailingAnchor.constraint(equalTo: trailingAnchor),
            contentView.bottomAnchor.constraint(equalTo: bottomAnchor),
        ])
    } 
    ...
}
  1. सामग्री collectionView(:cellForItemAt:)दृश्य की चौड़ाई को संग्रह दृश्य की चौड़ाई तक सीमित करने के लिए contentView.widthAnchor.constraint सेट करें ।

यह निम्नानुसार होता है; हम कलेक्टव्यू maxWidthकी चौड़ाई पर सेल के वैरिएबल को सेट करेंगे collectionView(:cellForItemAt:)और maxWidth's' की didSetविधि में हम BroadWnchor.constant को maxWidth पर सेट करेंगे।

class ViewController: UIViewController, UICollectionViewDataSource {
    ...

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! MultiLineCell
        cell.textView.text = dummyTextMessages[indexPath.row]
        cell.maxWidth = collectionView.frame.width
        return cell
    }

    ...
}
class MultiLineCell: UICollectionViewCell{
    ....

    var maxWidth: CGFloat? {
        didSet {
            guard let maxWidth = maxWidth else {
                return
            }
            contentViewWidthAnchor.constant = maxWidth
            contentViewWidthAnchor.isActive = true
        }
    }

    ....
}

चूंकि आप UITextView के स्व-आकार को सक्षम करना चाहते हैं, इसलिए इसमें एक अतिरिक्त चरण है;

4. UITextView की ऊंचाईअनचोर.संस्थान की गणना और सेट करें।

तो, जब भी contentView की चौड़ाई सेट कर दिया जाता है कि हम में साथ UITextView की ऊंचाई को समायोजित करेंगे didSetकी maxWidth

UICollectionViewCell के अंदर:

var maxWidth: CGFloat? {
    didSet {
        guard let maxWidth = maxWidth else {
            return
        }
        contentViewWidthAnchor.constant = maxWidth
        contentViewWidthAnchor.isActive = true

        let sizeToFitIn = CGSize(width: maxWidth, height: CGFloat(MAXFLOAT))
        let newSize = self.textView.sizeThatFits(sizeToFitIn)
        self.textViewHeightContraint.constant = newSize.height
    }
}

इन चरणों से आपको वांछित परिणाम मिलेगा। यहां एक संपूर्ण runnable है सार

अपने स्पष्ट और ज्ञानवर्धक ब्लॉग पोस्ट के लिए वादिम बुलविन का धन्यवाद - संग्रह देखें सेल स्व-आकार: ट्यूटोरियल द्वारा कदम


-2

मैंने उपयोग करने की कोशिश की, estimatedItemSizeलेकिन कोशिकाओं को डालने और हटाने के दौरान कीड़े का एक गुच्छा estimatedItemSizeथा, अगर सेल की ऊंचाई के बराबर नहीं था। मैंने estimatedItemSizeप्रोटोटाइप सेल का उपयोग करके गतिशील सेल की स्थापना और कार्यान्वयन को रोक दिया । यहां बताया गया है कि यह कैसे किया जाता है:

यह प्रोटोकॉल बनाएं:

protocol SizeableCollectionViewCell {
    func fittedSize(forConstrainedSize size: CGSize)->CGSize
}

इस प्रोटोकॉल को अपने रिवाज में लागू करें UICollectionViewCell:

class YourCustomCollectionViewCell: UICollectionViewCell, SizeableCollectionViewCell {

    @IBOutlet private var mTitle: UILabel!
    @IBOutlet private var mDescription: UILabel!
    @IBOutlet private var mContentView: UIView!
    @IBOutlet private var mTitleTopConstraint: NSLayoutConstraint!
    @IBOutlet private var mDesciptionBottomConstraint: NSLayoutConstraint!

    func fittedSize(forConstrainedSize size: CGSize)->CGSize {

        let fittedSize: CGSize!

        //if height is greatest value, then it's dynamic, so it must be calculated
        if size.height == CGFLoat.greatestFiniteMagnitude {

            var height: CGFloat = 0

            /*now here's where you want to add all the heights up of your views.
              apple provides a method called sizeThatFits(size:), but it's not 
              implemented by default; except for some concrete subclasses such 
              as UILabel, UIButton, etc. search to see if the classes you use implement 
              it. here's how it would be used:
            */
            height += mTitle.sizeThatFits(size).height
            height += mDescription.sizeThatFits(size).height
            height += mCustomView.sizeThatFits(size).height    //you'll have to implement this in your custom view

            //anything that takes up height in the cell has to be included, including top/bottom margin constraints
            height += mTitleTopConstraint.constant
            height += mDescriptionBottomConstraint.constant

            fittedSize = CGSize(width: size.width, height: height)
        }
        //else width is greatest value, if not, you did something wrong
        else {
            //do the same thing that's done for height but with width, remember to include leading/trailing margins in calculations
        }

        return fittedSize
    }
}

अब अपने नियंत्रक को इसके अनुरूप बनाएं UICollectionViewDelegateFlowLayout, और इस क्षेत्र में:

class YourViewController: UIViewController, UICollectionViewDelegateFlowLayout {
    private var mCustomCellPrototype = UINib(nibName: <name of the nib file for your custom collectionviewcell>, bundle: nil).instantiate(withOwner: nil, options: nil).first as! SizeableCollectionViewCell
}

इसका उपयोग डेटा को बाइंड करने के लिए एक प्रोटोटाइप सेल के रूप में किया जाएगा और फिर यह निर्धारित किया जाएगा कि उस डेटा ने उस आयाम को कैसे प्रभावित किया जिसे आप गतिशील बनाना चाहते हैं

अंत में, UICollectionViewDelegateFlowLayout's collectionView(:layout:sizeForItemAt:)लागू किया जाना है:

class YourViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {

    private var mDataSource: [CustomModel]

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath)->CGSize {

        //bind the prototype cell with the data that corresponds to this index path
        mCustomCellPrototype.bind(model: mDataSource[indexPath.row])    //this is the same method you would use to reconfigure the cells that you dequeue in collectionView(:cellForItemAt:). i'm calling it bind

        //define the dimension you want constrained
        let width = UIScreen.main.bounds.size.width - 20    //the width you want your cells to be
        let height = CGFloat.greatestFiniteMagnitude    //height has the greatest finite magnitude, so in this code, that means it will be dynamic
        let constrainedSize = CGSize(width: width, height: height)

        //determine the size the cell will be given this data and return it
        return mCustomCellPrototype.fittedSize(forConstrainedSize: constrainedSize)
    }
}

और बस। collectionView(:layout:sizeForItemAt:)इस तरह से सेल के आकार को वापस करना मुझे उपयोग करने से रोकता है estimatedItemSize, और कोशिकाओं को सम्मिलित करना और हटाना पूरी तरह से काम करता है।

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