FlowLayout के साथ UICollectionView की ऊंचाई का निर्धारण कैसे करें


118

मुझे एक के UICollectionViewसाथ मिला है UICollectionViewFlowLayout, और मैं इसकी सामग्री का आकार ( intrinsicContentSizeऑटोलिएट के माध्यम से इसकी ऊंचाई को समायोजित करने के लिए आवश्यक रिटर्न के लिए) की गणना करना चाहता हूं ।

समस्याएं हैं: यहां तक ​​कि अगर मेरे पास सभी कोशिकाओं के लिए एक निश्चित और समान ऊंचाई है, तो मुझे नहीं पता कि मेरे पास कितनी "पंक्तियाँ" / लाइनें हैं UICollectionView। मैं अपने डेटा स्रोत में आइटमों की संख्या से यह भी निर्धारित नहीं कर सकता, क्योंकि डेटा आइटम का प्रतिनिधित्व करने वाली कोशिकाएं चौड़ाई में भिन्न होती हैं, इसलिए परिणामस्वरूप आइटम की एक पंक्ति में मेरी संख्या होती है UICollectionView

चूँकि मैं आधिकारिक दस्तावेज़ीकरण में इस विषय पर कोई संकेत नहीं पा सका और गुगली ने मुझे आगे नहीं लाया, किसी भी मदद और विचारों की बहुत सराहना की जाएगी।

जवाबों:


254

वाह! किसी कारण से, घंटों के शोध के बाद, मुझे अब अपने प्रश्न का एक बहुत आसान उत्तर मिल गया: मैं पूरी तरह से गलत जगह पर खोज रहा था, सभी दस्तावेजों के माध्यम से खुदाई जो मुझे मिल सकती थी UICollectionView

सरल और आसान समाधान अंतर्निहित लेआउट में निहित है: बस collectionViewContentSizeअपनी myCollectionView.collectionViewLayoutसंपत्ति पर कॉल करें और आपको सामग्री की ऊंचाई और चौड़ाई के रूप में मिलती है CGSize। यह उतना ही आसान है।


1
वाह, काश यूआईटेबल व्यू में भी कुछ ऐसा ही होता
क्रिस चेन

1
इग्नाटुस, @jbandi, क्रिस एट अल, क्या आप इस पर विस्तार कर सकते हैं? जब मैंने एक बड़े अंतर-आइटम रिक्ति (ताकि आइटम क्षैतिज रूप से बाहर हो जाएं) के साथ एक क्षैतिज स्क्रॉल दिशा के साथ परीक्षण किया, तो संग्रह दृश्य ने एक अमान्य आंतरिक सामग्री आकार (-1, -1) लौटा दी, और संग्रहदृश्यसुविधा को प्रभावी रूप से वापस कर दिया। संग्रह दृश्य की सीमा - इस बात पर ध्यान नहीं दे रही थी कि केवल एक पंक्ति थी जो अंतरिक्ष से घिरी थी। संक्षेप में, यह बहुत आंतरिक नहीं था। धन्यवाद!
क्रिस कॉनवर

8
संग्रह दृश्य के बीच अंतर क्या है और स्क्रॉल दृश्य के अनुरूपण?
रौनक

जब आप viewDidLoad में संग्रह दृश्य की सामग्री को कॉल करते हैं, तो यह संग्रह दृश्य का फ्रेम लौटाता है, collectionViewContentSize रिटर्न सही सामग्री आकार देता है।
रोष

1
जिनके लिए यह मदद कर सकता है: मुझे इससे पहले एक "लेआउटआईएनडीड ()" करना था ताकि मैं इसे काम कर पाऊं।
अस्नली

37

यदि आप ऑटो लेआउट का उपयोग कर रहे हैं , तो आप एक उपवर्ग बना सकते हैंUICollectionView

यदि आप नीचे दिए गए कोड का उपयोग करते हैं, तो आपको संग्रह दृश्य के लिए कोई ऊँचाई की बाध्यता निर्दिष्ट करने की आवश्यकता नहीं है क्योंकि यह संग्रह दृश्य की सामग्री के आधार पर भिन्न होगा।

नीचे दिया गया कार्यान्वयन है:

@interface DynamicCollectionView : UICollectionView

@end

@implementation DynamicCollectionView

- (void) layoutSubviews
{
    [super layoutSubviews];

    if (!CGSizeEqualToSize(self.bounds.size, [self intrinsicContentSize]))
    {
        [self invalidateIntrinsicContentSize];
    }
}

- (CGSize)intrinsicContentSize
{
    CGSize intrinsicContentSize = self.contentSize;

    return intrinsicContentSize;
}

@end

12
मेरे लिए काम नहीं किया ... मैं एक UITableViewCell के अंदर अपने कलेक्शन व्यू का उपयोग कर रहा हूं और ऊंचाई में बढ़ने के लिए टेबलव्यू पसंद करूंगा क्योंकि iOS8 UITableViewAutomaticDimension का उपयोग करके संग्रह दृश्य ऊंचाई में बढ़ता है, लेकिन मेरा संग्रह छोटा रह गया है;
जॉर्ज

बहुत बढ़िया। एक UIScrollView के अंदर मेरे UICollectionView के लिए लघु और मीठा समाधान!
dotToString

2
एक महत्वपूर्ण बात संग्रह दृश्य में स्क्रॉलिंग और स्क्रॉलबार को अक्षम करना है
जॉर्ज

1
जॉर्ज के रूप में एक ही समस्या, यह लगभग 50px ऊंचाई में है जब यह 400 से अधिक होना चाहिए
xtrinch

3
हां, मैंने "स्क्रोलबे, नो स्कोलबार्स" के कलेक्शनव्यू को सेट किया और फिर इसे लोड किया फिर टेबलव्यू की सामग्री सेट की गई। साथ ही कलेक्शनव्यू एक उपवर्ग है जो इसे आंतरिक आकार देता है जैसा कि intrinsicContentSize। उम्मीद है की वो मदद करदे!
जॉर्ज

25

पर viewDidAppearआप इसे प्राप्त कर सकते हैं:

float height = self.myCollectionView.collectionViewLayout.collectionViewContentSize.height;

हो सकता है कि जब आप डेटा को पुनः लोड करते हैं, तब नए डेटा के साथ एक नई ऊंचाई की गणना करने की आवश्यकता होती है, तब आप इसे प्राप्त कर सकते हैं: सुनने के लिए पर्यवेक्षक जोड़ें जब आपका CollectionViewतैयार डेटा फिर से लोड हो viewdidload:

[self.myCollectionView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld context:NULL];

फिर नई ऊंचाई पाने के लिए बलो फंक्शन जोड़ें या फिर कलेक्शन खत्म होने के बाद कुछ भी करें:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary  *)change context:(void *)context
{
    //Whatever you do here when the reloadData finished
    float newHeight = self.myCollectionView.collectionViewLayout.collectionViewContentSize.height;    
}

और प्रेक्षक को दूर करने के लिए मत भूलना:

[self.myCollectionView removeObserver:self forKeyPath:@"contentSize" context:NULL];

11

स्विफ्ट में user1046037 उत्तर ...

class DynamicCollectionView: UICollectionView {
    override func layoutSubviews() {
        super.layoutSubviews()
        if bounds.size != intrinsicContentSize() {
            invalidateIntrinsicContentSize()
        }
    }

    override func intrinsicContentSize() -> CGSize {
        return self.contentSize
    }
}

यह पूरी तरह से काम कर रहा है, लेकिन अगर आपके पास UILabelऊपर जैसा कुछ है, तो ऊपर दिए collectionViewगए अन्य तत्व के पास से सामग्री , क्या आपके पास कोई और उपाय है?
नवंबर को कोलाकेन

11

User1046037 उत्तर के लिए स्विफ्ट 3 कोड

import UIKit

class DynamicCollectionView: UICollectionView {

    override func layoutSubviews() {
        super.layoutSubviews()
        if !__CGSizeEqualToSize(bounds.size, self.intrinsicContentSize) {
            self.invalidateIntrinsicContentSize()
        }

    }

    override var intrinsicContentSize: CGSize {
        return contentSize
    }

}

एक नवसिखुआ, और मुझे यकीन नहीं है कि मेरे ViewController में इसका उपयोग कहां और कैसे करना है, क्या आप कृपया उत्तर के साथ एक संपादन कर सकते हैं .....?
अबिरामी बाला

1
बस स्टोरीबोर्ड में अपने संग्रह के लिए इस वर्ग को सेट करें
मोहम्मद सादिक शेख

7

स्विफ्ट 4

class DynamicCollectionView: UICollectionView {
  override func layoutSubviews() {
    super.layoutSubviews()
    if !__CGSizeEqualToSize(bounds.size, self.intrinsicContentSize) {
      self.invalidateIntrinsicContentSize()
    }
  }

  override var intrinsicContentSize: CGSize {
    return collectionViewLayout.collectionViewContentSize
  }
}

1
मैंने पाया कि आईफोन 6/7 प्लस और एक्सआर, एक्सएस-मैक्स
राहुल के राजन

7

स्विफ्ट 4.2

class DynamicCollectionView: UICollectionView {
    override func layoutSubviews() {
        super.layoutSubviews()
        if bounds.size != intrinsicContentSize {
            invalidateIntrinsicContentSize()
        }
    }

    override var intrinsicContentSize: CGSize {
        return self.contentSize
    }
}

4

इस प्रश्न का उत्तर देने में बहुत देर हो चुकी है लेकिन मैं हाल ही में इस मुद्दे से गुज़रा हूँ।
@ ली का उपरोक्त उत्तर मुझे अपना उत्तर पाने में बहुत मदद करता है। लेकिन वह जवाब ऑब्जेक्टिव-सी तक सीमित है और मैं तेजी से काम कर रहा था ।
@ आपके उत्तर के संदर्भ में, मुझे स्विफ्ट उपयोगकर्ता को यह समस्या आसानी से हल करने दें। उसके लिए, कृपया नीचे दिए गए चरणों का पालन करें:

CGFloatघोषणा खंड में एक चर घोषित करें :

var height : CGFloat!

पर viewDidAppearआप इसे प्राप्त कर सकते हैं:

height = self.myCollectionView.collectionViewLayout.collectionViewContentSize().height

हो सकता है कि जब आप reloadडेटा तब नए डेटा के साथ एक नई ऊंचाई की गणना करने की आवश्यकता है तो आप इसे प्राप्त कर सकते हैं: addObserverसुनने के लिए जब आपका CollectionViewसमाप्त डेटा पुनः लोड करें viewWillAppear:

override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(true)
        ....
        ....
        self.shapeCollectionView.addObserver(self, forKeyPath: "contentSize", options: NSKeyValueObservingOptions.Old, context: nil)
    }

फिर नई ऊंचाई प्राप्त करने के लिए बलो फ़ंक्शन जोड़ें या collectionviewसमाप्त होने के बाद कुछ भी करें :

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
        let newHeight : CGFloat = self.myCollectionView.collectionViewLayout.collectionViewContentSize().height

        var frame : CGRect! = self.myCollectionView.frame
        frame.size.height = newHeight

        self.myCollectionView.frame = frame
    }

और प्रेक्षक को दूर करने के लिए मत भूलना:

override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(true)
    ....
    ....
    self.myCollectionView.removeObserver(self, forKeyPath: "contentSize")
}

मुझे उम्मीद है कि यह आपके मुद्दे को तेजी से हल करने में मदद करेगा।


@ शिखाशर्मा: आप "ViewDidDisappear" पद्धति के भीतर रिमूवर कोड जोड़ सकते हैं, जो देखने की पुष्टि होने के बाद ही पर्यवेक्षक को हटा देगा। कृपया अद्यतन उत्तर की जाँच करें।
एर। विहार

मुझे यह त्रुटि मिल रही है: An -oberveValueForKeyPath: OfObject: परिवर्तन: संदर्भ: संदेश प्राप्त हुआ था, लेकिन संभाला नहीं गया था।
शिखा शर्मा

@ शिखा शर्मा: क्षमा करें, यह विधि निर्दिष्ट करने की मेरी गलती है। हटाने का प्रयास करें viewWillDisappear में removeobserver कोड डालें।
एर।

1

यह उत्तर @Er पर आधारित है। विहार का उत्तर। आप RxSwift का उपयोग करके आसानी से समाधान को लागू कर सकते हैं

     collectionView.rx.observe(CGSize.self , "contentSize").subscribe(onNext: { (size) in
        print("sizer \(size)")
    }).disposed(by: rx.disposeBag)

0

@ User1046037 का स्विफ्ट संस्करण:

public class DynamicCollectionView: UICollectionView {

    override public func layoutSubviews() {
        super.layoutSubviews()
        if !bounds.size.equalTo(intrinsicContentSize) {
            invalidateIntrinsicContentSize()
        }
    }

    override public var intrinsicContentSize: CGSize {
        let intrinsicContentSize: CGSize = contentSize
        return intrinsicContentSize
    }
}

0

स्विफ्ट 4.2, Xcode 10.1, iOS 12.1:

किसी कारण से, collectionView.contentSize.heightमेरे संग्रह दृश्य की हल की गई ऊंचाई से छोटा दिखाई दे रहा था। सबसे पहले, मैं सुपरवाइवे की ऊंचाई के 1/2 के सापेक्ष एक ऑटो-लेआउट बाधा का उपयोग कर रहा था। इसे ठीक करने के लिए, मैंने दृष्टि के "सुरक्षित क्षेत्र" के सापेक्ष बाधा को बदल दिया।

इसने मुझे अपने संग्रह दृश्य को उपयोग करने के लिए सेल ऊंचाई सेट करने की अनुमति दी collectionView.contentSize.height:

private func setCellSize() {
    let height: CGFloat = (collectionView.contentSize.height) / CGFloat(numberOfRows)
    let width: CGFloat = view.frame.width - CGFloat(horizontalCellMargin * 2)

    let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
    layout.itemSize = CGSize(width: width, height: height)
}

इससे पहले

पर्यवेक्षण के सापेक्ष ऊंचाई की बाधा खराब सिम्युलेटर परिणाम

उपरांत

ऊंचाई क्षेत्र सुरक्षित क्षेत्र के सापेक्ष अच्छा सिम्युलेटर परिणाम


0

आपके संग्रहण दृश्य को संग्रह दृश्य नाम दिया गया है, जिसे आप निम्नानुसार ऊँचाई पर ले जा सकते हैं।

let height = collectionView.collectionViewLayout.collectionViewContentSize.height

0

इसके अलावा reloadDataheight आप ऊँचाई प्राप्त करने से पहले बेहतर कॉल करेंगे :

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