UICollectionView में बाईं ओर सेल संरेखित करें


95

मैं अपनी परियोजना में एक UICollectionView का उपयोग कर रहा हूं, जहां एक लाइन पर अलग-अलग चौड़ाई के कई सेल हैं। के अनुसार: https://developer.apple.com/library/content/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/UsingtheFlowLayout/UsingtheFlowLout.html

यह समान पैडिंग के साथ लाइन के बाहर कोशिकाओं को फैलाता है। यह अपेक्षा के अनुसार होता है, सिवाय इसके कि मैं उन्हें औचित्य देना चाहता हूं, और हार्ड कोड एक पेडिंग चौड़ाई।

मुझे लगता है कि मुझे UICollectionViewFlowLayout को उप-वर्ग करने की आवश्यकता है, हालांकि कुछ ट्यूटोरियल आदि को पढ़ने के बाद मुझे लगता है कि यह कैसे काम करता है।


जवाबों:


169

इस थ्रेड में अन्य समाधान ठीक से काम नहीं करते हैं, जब लाइन केवल 1 आइटम द्वारा बनाई जाती है या जटिल होती है।

रयान द्वारा दिए गए उदाहरण के आधार पर, मैंने नए तत्व की वाई स्थिति का निरीक्षण करके एक नई रेखा का पता लगाने के लिए कोड को बदल दिया। प्रदर्शन में बहुत सरल और त्वरित।

स्विफ्ट:

class LeftAlignedCollectionViewFlowLayout: UICollectionViewFlowLayout {

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let attributes = super.layoutAttributesForElements(in: rect)

        var leftMargin = sectionInset.left
        var maxY: CGFloat = -1.0
        attributes?.forEach { layoutAttribute in
            if layoutAttribute.frame.origin.y >= maxY {
                leftMargin = sectionInset.left
            }

            layoutAttribute.frame.origin.x = leftMargin

            leftMargin += layoutAttribute.frame.width + minimumInteritemSpacing
            maxY = max(layoutAttribute.frame.maxY , maxY)
        }

        return attributes
    }
}

यदि आप पूरक विचार रखना चाहते हैं, तो उनका आकार रखें, forEachकॉल में बंद होने के शीर्ष पर निम्नलिखित जोड़ें :

guard layoutAttribute.representedElementCategory == .cell else {
    return
}

उद्देश्य सी:

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSArray *attributes = [super layoutAttributesForElementsInRect:rect];

    CGFloat leftMargin = self.sectionInset.left; //initalized to silence compiler, and actaully safer, but not planning to use.
    CGFloat maxY = -1.0f;

    //this loop assumes attributes are in IndexPath order
    for (UICollectionViewLayoutAttributes *attribute in attributes) {
        if (attribute.frame.origin.y >= maxY) {
            leftMargin = self.sectionInset.left;
        }

        attribute.frame = CGRectMake(leftMargin, attribute.frame.origin.y, attribute.frame.size.width, attribute.frame.size.height);

        leftMargin += attribute.frame.size.width + self.minimumInteritemSpacing;
        maxY = MAX(CGRectGetMaxY(attribute.frame), maxY);
    }

    return attributes;
}

4
धन्यवाद! मुझे एक चेतावनी मिल रही थी, जो सरणी में विशेषताओं की एक प्रति बनाकर तय की गई है let attributes = super.layoutAttributesForElementsInRect(rect)?.map { $0.copy() as! UICollectionViewLayoutAttributes }
tkuichooseyou

2
किसी के लिए जो इस केंद्र-संरेखित संस्करण की तलाश में इस पर ठोकर खाई हो सकती है, जैसा कि मैंने किया था, मैंने यहाँ एंजेल के उत्तर का एक संशोधित संस्करण पोस्ट किया है: stackoverflow.com/a/38254368/2845237
एलेक्स कोशी

मैंने इस समाधान की कोशिश की, लेकिन संग्रह दृश्य के दाईं ओर स्थित सेल के कुछ संग्रह दृश्य की सीमा से अधिक है। क्या किसी और से इसका सामना हुआ?
हैप्पीहैपी

@ हेप्पीहप्पी मुझे भी यही व्यवहार आता है। कोई फिक्स?
जॉन बॉम

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

61

इस प्रश्न के उत्तर में कई महान विचार शामिल हैं। हालांकि, उनमें से अधिकांश में कुछ कमियां हैं:

  • समाधान जो सेल के y मान की जांच नहीं करते हैं वे केवल एकल-पंक्ति लेआउट के लिए काम करते हैं । वे कई लाइनों के साथ संग्रह दृश्य लेआउट के लिए असफल हो जाते हैं।
  • समाधान है कि कर जाँच y की तरह मूल्य एंजेल गार्सिया Olloqui का जवाब केवल काम करता है, तो सभी कोशिकाओं में एक ही ऊंचाई है । वे एक चर ऊंचाई के साथ कोशिकाओं के लिए असफल होते हैं।
  • अधिकांश समाधान केवल layoutAttributesForElements(in rect: CGRect)फ़ंक्शन को ओवरराइड करते हैं। वे ओवरराइड नहीं करते हैं layoutAttributesForItem(at indexPath: IndexPath)यह एक समस्या है क्योंकि संग्रह दृश्य समय-समय पर एक विशेष सूचकांक पथ के लिए लेआउट विशेषताओं को पुनः प्राप्त करने के लिए बाद के फ़ंक्शन को कॉल करता है। यदि आप उस फ़ंक्शन से उचित विशेषताओं को वापस नहीं करते हैं, तो आप सभी प्रकार के दृश्य बगों में भाग लेने की संभावना रखते हैं, जैसे कि कक्षों के सम्मिलन और विलोपन एनिमेशन के दौरान या संग्रह दृश्य लेआउट की स्थापना करके स्वयं-आकार वाले कक्षों का उपयोग करते समय estimatedItemSizeएप्पल डॉक्स राज्य:

    प्रत्येक कस्टम लेआउट ऑब्जेक्ट से layoutAttributesForItemAtIndexPath:विधि को लागू करने की अपेक्षा की जाती है ।

  • कई समाधान फ़ंक्शन के rectलिए पारित पैरामीटर के बारे में भी धारणा बनाते हैं layoutAttributesForElements(in rect: CGRect)। उदाहरण के लिए, कई इस धारणा पर आधारित हैं कि rectहमेशा एक नई लाइन की शुरुआत होती है जो जरूरी नहीं है।

तो दूसरे शब्दों में:

इस पृष्ठ पर सुझाए गए अधिकांश समाधान कुछ विशिष्ट अनुप्रयोगों के लिए काम करते हैं, लेकिन वे हर स्थिति में अपेक्षित रूप से काम नहीं करते हैं।


AlignedCollectionViewFlowLayout

इन मुद्दों को हल करने के लिए मैंने एक UICollectionViewFlowLayoutउपवर्ग बनाया है जो एक समान विचार का अनुसरण करता है जैसा कि मैट और क्रिस वैगनर ने एक समान प्रश्न के उत्तर में दिया था । यह या तो कोशिकाओं को संरेखित कर सकता है

⬅︎ बायाँ :

वाम-संरेखित लेआउट

या ➡︎ सही :

दायां-संरेखित लेआउट

और इसके अलावा कोशिकाओं को उनकी संबंधित पंक्तियों में लंबवत रूप से संरेखित करने के विकल्प प्रदान करता है (यदि वे ऊंचाई में भिन्न हैं)।

आप बस इसे यहाँ डाउनलोड कर सकते हैं:

https://github.com/mischa-hildebrand/AlignedCollectionViewFlowLayout

उपयोग सीधे आगे है और README फ़ाइल में समझाया गया है। आप मूल रूप से एक उदाहरण बनाते AlignedCollectionViewFlowLayoutहैं, वांछित संरेखण निर्दिष्ट करते हैं और इसे अपने संग्रह दृश्य की collectionViewLayoutसंपत्ति में निर्दिष्ट करते हैं:

 let alignedFlowLayout = AlignedCollectionViewFlowLayout(horizontalAlignment: .left, 
                                                         verticalAlignment: .top)

 yourCollectionView.collectionViewLayout = alignedFlowLayout

(यह कोकोपोड्स पर भी उपलब्ध है ।)


यह कैसे काम करता है (बाएं-संरेखित कोशिकाओं के लिए):

यहाँ अवधारणा पूरी तरह से layoutAttributesForItem(at indexPath: IndexPath)कार्य पर निर्भर है । में layoutAttributesForElements(in rect: CGRect)हम बस के भीतर सभी सेल के सूचकांक पथ पाने rectऔर उसके बाद हर सूचकांक पथ सही फ्रेम को पुनः प्राप्त करने के लिए पहली फ़ंक्शन को कॉल करें:

override public func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {

    // We may not change the original layout attributes 
    // or UICollectionViewFlowLayout might complain.
    let layoutAttributesObjects = copy(super.layoutAttributesForElements(in: rect))

    layoutAttributesObjects?.forEach({ (layoutAttributes) in
        if layoutAttributes.representedElementCategory == .cell { // Do not modify header views etc.
            let indexPath = layoutAttributes.indexPath
            // Retrieve the correct frame from layoutAttributesForItem(at: indexPath):
            if let newFrame = layoutAttributesForItem(at: indexPath)?.frame {
                layoutAttributes.frame = newFrame
            }
        }
    })

    return layoutAttributesObjects
}

( copy()फ़ंक्शन केवल सरणी में सभी लेआउट विशेषताओं की एक गहरी प्रतिलिपि बनाता है। आप इसके कार्यान्वयन के लिए स्रोत कोड देख सकते हैं ।)

इसलिए अब हमें केवल यही करना है कि layoutAttributesForItem(at indexPath: IndexPath)फ़ंक्शन को ठीक से लागू करें । सुपर क्लास UICollectionViewFlowLayoutपहले से ही प्रत्येक पंक्ति में सही संख्या में कोशिकाओं को रखता है इसलिए हमें केवल उन्हें अपनी संबंधित पंक्ति में छोड़ देना होगा। कठिनाई प्रत्येक कक्ष को बाईं ओर स्थानांतरित करने के लिए आवश्यक अंतरिक्ष की मात्रा की गणना करने में निहित है।

जैसा कि हम चाहते हैं कि कोशिकाओं के बीच एक निश्चित रिक्ति हो जो मुख्य विचार है, बस यह मान लें कि पिछली सेल (वर्तमान में रखी गई सेल का सेल शेष है) पहले से ही ठीक से तैनात है। फिर हमें केवल maxXपिछले सेल के फ्रेम के मूल्य में सेल स्पेसिंग को जोड़ना होगा और origin.xवर्तमान सेल के फ्रेम के लिए वैल्यू।

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

यह जानने के लिए कि क्या इंडेक्स I पर सेल इंडेक्स I-1 के साथ सेल के समान है ...

 +---------+----------------------------------------------------------------+---------+
 |         |                                                                |         |
 |         |     +------------+                                             |         |
 |         |     |            |                                             |         |
 | section |- - -|- - - - - - |- - - - +---------------------+ - - - - - - -| section |
 |  inset  |     |intersection|        |                     |   line rect  |  inset  |
 |         |- - -|- - - - - - |- - - - +---------------------+ - - - - - - -|         |
 | (left)  |     |            |             current item                    | (right) |
 |         |     +------------+                                             |         |
 |         |     previous item                                              |         |
 +---------+----------------------------------------------------------------+---------+

... मैं वर्तमान सेल के चारों ओर एक आयत बनाता हूं और इसे पूरे संग्रह दृश्य की चौड़ाई पर फैलाता हूं। UICollectionViewFlowLayoutकेंद्र के रूप में सभी कोशिकाएं लंबवत रूप से एक ही पंक्ति में प्रत्येक सेल को इस आयत के साथ अंतर करना चाहिए

इस प्रकार, मैं केवल यह जांचता हूं कि क्या इंडेक्स I-1 के साथ सेल इस लाइन आयत के साथ सेल से बनाई गई है जो इंडेक्स i के साथ सेल से बनाई गई है ।

  • यदि यह इंटरसेक्ट करता है, तो इंडेक्स I वाला सेल लाइन में सबसे लेफ्ट सेल नहीं है।
    → पिछले सेल का फ्रेम प्राप्त करें (इंडेक्स i and 1 के साथ ) और इसके बगल में वर्तमान सेल को स्थानांतरित करें।

  • यदि यह प्रतिच्छेद नहीं करता है, तो सूचकांक I वाला कक्ष पंक्ति में सबसे बाईं ओर का कक्ष है।
    → संग्रह दृश्य के बाएँ किनारे पर सेल ले जाएँ (इसकी ऊर्ध्वाधर स्थिति को बदले बिना)।

मैं layoutAttributesForItem(at indexPath: IndexPath)यहां फ़ंक्शन के वास्तविक कार्यान्वयन को पोस्ट नहीं करूंगा क्योंकि मुझे लगता है कि सबसे महत्वपूर्ण हिस्सा विचार को समझना है और आप हमेशा स्रोत कोड में मेरे कार्यान्वयन की जांच कर सकते हैं । (यह यहाँ समझाया गया है की तुलना में थोड़ा अधिक जटिल है क्योंकि मैं .rightसंरेखण और विभिन्न ऊर्ध्वाधर संरेखण विकल्पों की अनुमति देता हूं । हालांकि, यह एक ही विचार का अनुसरण करता है।)


वाह, मुझे लगता है कि यह सबसे लंबा जवाब है जो मैंने कभी स्टैकओवरफ़्लो पर लिखा है। आशा है कि ये आपकी मदद करेगा। 😉


मैं इस परिदृश्य के साथ आवेदन करता हूं stackoverflow.com/questions/56349052/… लेकिन यह काम नहीं कर रहा है। क्या आप मुझे बता सकते हैं कि मैं इसे कैसे हासिल कर सकता हूँ
नज़्मुल हसन

यहां तक ​​कि इसके साथ (जो कि वास्तव में बहुत बढ़िया प्रोजेक्ट है) मुझे अपने ऐप्स वर्टिकल स्क्रॉलिंग कलेक्शन व्यू में फ्लैशिंग का अनुभव है। मेरे पास 20 सेल हैं, और पहली स्क्रॉल पर, पहली सेल खाली है और सभी सेल दाईं ओर एक स्थिति में स्थानांतरित हो गए हैं। एक पूर्ण स्क्रॉल अप और डाउन के बाद, चीजें ठीक से संरेखित होती हैं।
पार्थ तामने

बहुत बढ़िया प्रोजेक्ट! यह देखना बहुत अच्छा होगा कि यह कार्थेज के लिए सक्षम है।
पज्जुइलुनास 14

30

अपनी आवश्यकताओं के अनुसार, स्विफ्ट 4.1 और आईओएस 11 के साथ, आप अपनी समस्या को ठीक करने के लिए 2 पूर्ण कार्यान्वयनों में से एक का चयन कर सकते हैं ।


# 1। बाएं संरेखित ऑटोरेस्पिरिंग UICollectionViewCells

नीचे दिए गए कार्यान्वयन से पता चलता है कि ऑटोरेस्पोन्डिंग कोशिकाओं को बाईं ओर संरेखित करने के लिए UICollectionViewLayout's layoutAttributesForElements(in:), UICollectionViewFlowLayout' estimatedItemSizeऔर UILabel's का उपयोग कैसे preferredMaxLayoutWidthकरें UICollectionView:

CollectionViewController.swift

import UIKit

class CollectionViewController: UICollectionViewController {

    let array = ["1", "1 2", "1 2 3 4 5 6 7 8", "1 2 3 4 5 6 7 8 9 10 11", "1 2 3", "1 2 3 4", "1 2 3 4 5 6", "1 2 3 4 5 6 7 8 9 10", "1 2 3 4", "1 2 3 4 5 6 7", "1 2 3 4 5 6 7 8 9", "1", "1 2 3 4 5", "1", "1 2 3 4 5 6"]

    let columnLayout = FlowLayout(
        minimumInteritemSpacing: 10,
        minimumLineSpacing: 10,
        sectionInset: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
    )

    override func viewDidLoad() {
        super.viewDidLoad()

        collectionView?.collectionViewLayout = columnLayout
        collectionView?.contentInsetAdjustmentBehavior = .always
        collectionView?.register(CollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return array.count
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
        cell.label.text = array[indexPath.row]
        return cell
    }

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        collectionView?.collectionViewLayout.invalidateLayout()
        super.viewWillTransition(to: size, with: coordinator)
    }

}

FlowLayout.swift

import UIKit

class FlowLayout: UICollectionViewFlowLayout {

    required init(minimumInteritemSpacing: CGFloat = 0, minimumLineSpacing: CGFloat = 0, sectionInset: UIEdgeInsets = .zero) {
        super.init()

        estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize
        self.minimumInteritemSpacing = minimumInteritemSpacing
        self.minimumLineSpacing = minimumLineSpacing
        self.sectionInset = sectionInset
        sectionInsetReference = .fromSafeArea
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let layoutAttributes = super.layoutAttributesForElements(in: rect)!.map { $0.copy() as! UICollectionViewLayoutAttributes }
        guard scrollDirection == .vertical else { return layoutAttributes }

        // Filter attributes to compute only cell attributes
        let cellAttributes = layoutAttributes.filter({ $0.representedElementCategory == .cell })

        // Group cell attributes by row (cells with same vertical center) and loop on those groups
        for (_, attributes) in Dictionary(grouping: cellAttributes, by: { ($0.center.y / 10).rounded(.up) * 10 }) {
            // Set the initial left inset
            var leftInset = sectionInset.left

            // Loop on cells to adjust each cell's origin and prepare leftInset for the next cell
            for attribute in attributes {
                attribute.frame.origin.x = leftInset
                leftInset = attribute.frame.maxX + minimumInteritemSpacing
            }
        }

        return layoutAttributes
    }

}

CollectionViewCell.swift

import UIKit

class CollectionViewCell: UICollectionViewCell {

    let label = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)

        contentView.backgroundColor = .orange
        label.preferredMaxLayoutWidth = 120
        label.numberOfLines = 0

        contentView.addSubview(label)
        label.translatesAutoresizingMaskIntoConstraints = false
        contentView.layoutMarginsGuide.topAnchor.constraint(equalTo: label.topAnchor).isActive = true
        contentView.layoutMarginsGuide.leadingAnchor.constraint(equalTo: label.leadingAnchor).isActive = true
        contentView.layoutMarginsGuide.trailingAnchor.constraint(equalTo: label.trailingAnchor).isActive = true
        contentView.layoutMarginsGuide.bottomAnchor.constraint(equalTo: label.bottomAnchor).isActive = true
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

अपेक्षित परिणाम:

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


# 2। UICollectionViewCellतय आकार के साथ बाएँ संरेखित करें

नीचे दिया कार्यान्वयन कैसे उपयोग करने के लिए UICollectionViewLayoutकी layoutAttributesForElements(in:)और UICollectionViewFlowLayoutकी itemSizeएक में पूर्वनिर्धारित आकार के साथ छोड़ दिया संरेखित कोशिकाओं के क्रम में UICollectionView:

CollectionViewController.swift

import UIKit

class CollectionViewController: UICollectionViewController {

    let columnLayout = FlowLayout(
        itemSize: CGSize(width: 140, height: 140),
        minimumInteritemSpacing: 10,
        minimumLineSpacing: 10,
        sectionInset: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
    )

    override func viewDidLoad() {
        super.viewDidLoad()

        collectionView?.collectionViewLayout = columnLayout
        collectionView?.contentInsetAdjustmentBehavior = .always
        collectionView?.register(CollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 7
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
        return cell
    }

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        collectionView?.collectionViewLayout.invalidateLayout()
        super.viewWillTransition(to: size, with: coordinator)
    }

}

FlowLayout.swift

import UIKit

class FlowLayout: UICollectionViewFlowLayout {

    required init(itemSize: CGSize, minimumInteritemSpacing: CGFloat = 0, minimumLineSpacing: CGFloat = 0, sectionInset: UIEdgeInsets = .zero) {
        super.init()

        self.itemSize = itemSize
        self.minimumInteritemSpacing = minimumInteritemSpacing
        self.minimumLineSpacing = minimumLineSpacing
        self.sectionInset = sectionInset
        sectionInsetReference = .fromSafeArea
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let layoutAttributes = super.layoutAttributesForElements(in: rect)!.map { $0.copy() as! UICollectionViewLayoutAttributes }
        guard scrollDirection == .vertical else { return layoutAttributes }

        // Filter attributes to compute only cell attributes
        let cellAttributes = layoutAttributes.filter({ $0.representedElementCategory == .cell })

        // Group cell attributes by row (cells with same vertical center) and loop on those groups
        for (_, attributes) in Dictionary(grouping: cellAttributes, by: { ($0.center.y / 10).rounded(.up) * 10 }) {
            // Set the initial left inset
            var leftInset = sectionInset.left

            // Loop on cells to adjust each cell's origin and prepare leftInset for the next cell
            for attribute in attributes {
                attribute.frame.origin.x = leftInset
                leftInset = attribute.frame.maxX + minimumInteritemSpacing
            }
        }

        return layoutAttributes
    }

}

CollectionViewCell.swift

import UIKit

class CollectionViewCell: UICollectionViewCell {

    override init(frame: CGRect) {
        super.init(frame: frame)

        contentView.backgroundColor = .cyan
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

अपेक्षित परिणाम:

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


पंक्ति द्वारा सेल विशेषताओं को समूहीकृत करते समय, 10एक मनमानी संख्या का उपयोग होता है ?
अमरदीयन

25

2019 में सरल समाधान

यह उन निराशाजनक सवालों में से एक है जहां पिछले कुछ वर्षों में चीजें बहुत बदल गई हैं। यह अब आसान है।

मूल रूप से आप ऐसा करते हैं:

    // as you move across one row ...
    a.frame.origin.x = x
    x += a.frame.width + minimumInteritemSpacing
    // and, obviously start fresh again each row

अब आपको केवल बॉयलरप्लेट कोड की आवश्यकता है:

override func layoutAttributesForElements(
                  in rect: CGRect)->[UICollectionViewLayoutAttributes]? {
    
    guard let att = super.layoutAttributesForElements(in: rect) else { return [] }
    var x: CGFloat = sectionInset.left
    var y: CGFloat = -1.0
    
    for a in att {
        if a.representedElementCategory != .cell { continue }
        
        if a.frame.origin.y >= y { x = sectionInset.left }
        
        a.frame.origin.x = x
        x += a.frame.width + minimumInteritemSpacing
        
        y = a.frame.maxY
    }
    return att
}

बस कॉपी और पेस्ट करें कि UICollectionViewFlowLayoutआप - आप कर रहे हैं।

कॉपी और पेस्ट करने के लिए पूर्ण कार्य समाधान:

ये है पूरी बात:

class TagsLayout: UICollectionViewFlowLayout {
    
    required override init() {super.init(); common()}
    required init?(coder aDecoder: NSCoder) {super.init(coder: aDecoder); common()}
    
    private func common() {
        estimatedItemSize = UICollectionViewFlowLayout.automaticSize
        minimumLineSpacing = 10
        minimumInteritemSpacing = 10
    }
    
    override func layoutAttributesForElements(
                    in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        
        guard let att = super.layoutAttributesForElements(in:rect) else {return []}
        var x: CGFloat = sectionInset.left
        var y: CGFloat = -1.0
        
        for a in att {
            if a.representedElementCategory != .cell { continue }
            
            if a.frame.origin.y >= y { x = sectionInset.left }
            a.frame.origin.x = x
            x += a.frame.width + minimumInteritemSpacing
            y = a.frame.maxY
        }
        return att
    }
}

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

और अंत में...

ऊपर @AlexShubin को धन्यवाद दें जिन्होंने पहले यह स्पष्ट किया!


अरे। मै थोड़ा अस्पष्ट हूँ। प्रारंभ और समाप्ति पर हर स्ट्रिंग के लिए स्थान जोड़ना अभी भी आइटम सेल w / o में मेरे शब्द को दर्शाता है जो मैंने जोड़ा है। कैसे करना है इसका कोई अंदाजा?
मोहम्मद ली

यदि आप अपने संग्रह दृश्य में अनुभाग हेडर हैं, तो यह उन्हें मारने के लिए लगता है।
टायलरजम्स

22

इस सवाल पर कुछ समय बीत चुका है लेकिन इसका कोई जवाब नहीं है और यह एक अच्छा सवाल है। उत्तर UICollectionViewFlowLayout उपवर्ग में एक विधि को ओवरराइड करने के लिए है:

@implementation MYFlowLayoutSubclass

//Note, the layout's minimumInteritemSpacing (default 10.0) should not be less than this. 
#define ITEM_SPACING 10.0f

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {

    NSArray *attributesForElementsInRect = [super layoutAttributesForElementsInRect:rect];
    NSMutableArray *newAttributesForElementsInRect = [[NSMutableArray alloc] initWithCapacity:attributesForElementsInRect.count];

    CGFloat leftMargin = self.sectionInset.left; //initalized to silence compiler, and actaully safer, but not planning to use.

    //this loop assumes attributes are in IndexPath order
    for (UICollectionViewLayoutAttributes *attributes in attributesForElementsInRect) {
        if (attributes.frame.origin.x == self.sectionInset.left) {
            leftMargin = self.sectionInset.left; //will add outside loop
        } else {
            CGRect newLeftAlignedFrame = attributes.frame;
            newLeftAlignedFrame.origin.x = leftMargin;
            attributes.frame = newLeftAlignedFrame;
        }

        leftMargin += attributes.frame.size.width + ITEM_SPACING;
        [newAttributesForElementsInRect addObject:attributes];
    }   

    return newAttributesForElementsInRect;
}

@end

जैसा कि Apple द्वारा सिफारिश की गई है, आपको सुपर और उन पर पुनरावृति से लेआउट विशेषताएँ मिलती हैं। यदि यह पंक्ति में पहला है (इसके मूल द्वारा परिभाषित किया गया है। x बाईं ओर मार्जिन पर है), तो आप इसे अकेला छोड़ देते हैं और x को शून्य पर रीसेट करते हैं। फिर पहली सेल और हर सेल के लिए, आप उस सेल की चौड़ाई और कुछ मार्जिन जोड़ते हैं। यह लूप में अगले आइटम पर जाता है। यदि यह पहला आइटम नहीं है, तो आप चल रहे परिकलित मार्जिन पर मूल। X सेट करते हैं, और सरणी में नए तत्व जोड़ते हैं।


मुझे लगता है कि यह क्रिस वैगनर के समाधान ( stackoverflow.com/a/15554667/482557 ) से बेहतर है कि जुड़े हुए सवाल पर आपके कार्यान्वयन में शून्य दोहराव वाले UICollectionViewLayout कॉल हैं।
इवान आर

1
यदि पंक्ति में एकल आइटम नहीं है, तो यह इस तरह नहीं दिखता है क्योंकि UICollectionViewFlowLayout इसे केंद्र बनाता है। आप समस्या को हल करने के लिए केंद्र की जाँच कर सकते हैं। कुछ इस तरहattribute.center.x == self.collectionView?.bounds.midX
रयान पूलोस

मैंने इसे लागू किया, लेकिन किसी कारण से यह पहले खंड के लिए टूट गया: पहली सेल पहली पंक्ति के बाईं ओर दिखाई देती है, और दूसरी सेल (जो एक ही पंक्ति पर फिट नहीं होती है) अगली पंक्ति में जाती है, लेकिन शेष नहीं गठबंधन। इसके बजाय, इसकी एक्स स्थिति शुरू होती है जहां पहला सेल समाप्त होता है।
निकोलस मिआरी

@ निकोलसमीरी लूप यह एक नई पंक्ति तय करता है और चेक के leftMarginसाथ रीसेट करता है if (attributes.frame.origin.x == self.sectionInset.left) {। यह मानता है कि डिफ़ॉल्ट लेआउट ने नई पंक्ति के सेल को इसके साथ फ्लश करने के लिए संरेखित किया है sectionInset.left। यदि यह मामला नहीं है, तो आपके द्वारा वर्णित व्यवहार का परिणाम होगा। मैं लूप के अंदर एक विराम बिंदु सम्मिलित करूंगा और तुलना करने से ठीक पहले दूसरी पंक्ति की सेल के लिए दोनों पक्षों की जांच करूंगा। शुभकामनाएँ।
माइक सैंड

3
धन्यवाद ... मैंने UICollectionViewLeftAlignedLayout का उपयोग करके समाप्त कर दिया: github.com/mokagio/UICollectionViewLeftAlignedLayout । यह एक जोड़े को अधिक तरीकों से आगे निकलता है।
निकोलस मियारी Nic

9

मुझे एक ही समस्या थी, कोकोपोड को यूआईसीओलेक्टियन व्यू लिफ़्ट- एलाग्ड लियूटआउट आज़माएं। बस इसे अपनी परियोजना में शामिल करें और इसे इस तरह शुरू करें:

UICollectionViewLeftAlignedLayout *layout = [[UICollectionViewLeftAlignedLayout alloc] init];
UICollectionView *leftAlignedCollectionView = [[UICollectionView alloc] initWithFrame:frame collectionViewLayout:layout];

वहाँ लेआउट के अपने प्रारंभिककरण में एक उद्घाटन वर्ग ब्रैकेट गुम
रयानऑफ़कोर्स

मैंने दो उत्तर github.com/eroth/ERJustifiedFlowLayout और UICollectionViewLeftAlignedLayout का परीक्षण किया । केवल एक दूसरे ने सही परिणाम का उत्पादन किया जब अनुमान लगाया गया कि इसका उपयोग करें (स्व-आकार)।
EckhardN

5

माइकल सैंड के जवाब पर बिल्डिंग , मैंने एक उपवर्ग बनायाUICollectionViewFlowLayout बाएं, दाएं या पूर्ण (मूल रूप से डिफ़ॉल्ट) क्षैतिज औचित्य करने के लिए पुस्तकालय - यह आपको प्रत्येक सेल के बीच पूर्ण दूरी निर्धारित करने की भी सुविधा देता है। मैं इसमें क्षैतिज केंद्र औचित्य और ऊर्ध्वाधर औचित्य जोड़ने की योजना भी बना रहा हूं।

https://github.com/eroth/ERJustifiedFlowLayout


5

यहाँ स्विफ्ट में मूल उत्तर है। यह अभी भी ज्यादातर काम करता है।

class LeftAlignedFlowLayout: UICollectionViewFlowLayout {

    private override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let attributes = super.layoutAttributesForElementsInRect(rect)

        var leftMargin = sectionInset.left

        attributes?.forEach { layoutAttribute in
            if layoutAttribute.frame.origin.x == sectionInset.left {
                leftMargin = sectionInset.left
            }
            else {
                layoutAttribute.frame.origin.x = leftMargin
            }

            leftMargin += layoutAttribute.frame.width + minimumInteritemSpacing
        }

        return attributes
    }
}

अपवाद: ऑटोसाइजिंग सेल

दुख की बात है कि एक बड़ा अपवाद है। आप उपयोग कर रहे हैं UICollectionViewFlowLayout'एस estimatedItemSize। आंतरिक रूप UICollectionViewFlowLayoutसे चीजें थोड़ी बदल रही हैं। मैंने इसे पूरी तरह से नीचे ट्रैक नहीं किया है, लेकिन इसकी सेलिंग के अन्य तरीकों को स्पष्ट करने के बाद, layoutAttributesForElementsInRectजबकि सेल्फ साइज़िंग सेल। अपने परीक्षण और त्रुटि से मैंने पाया कि यह layoutAttributesForItemAtIndexPathप्रत्येक सेल के लिए व्यक्तिगत रूप से कॉल करने के दौरान अधिक बार ऑटोसाइज़ करने के लिए लगता है । इस अद्यतन के LeftAlignedFlowLayoutसाथ महान काम करता है estimatedItemSize। यह स्थिर आकार की कोशिकाओं के साथ भी काम करता है, हालांकि अतिरिक्त लेआउट कॉल मुझे मूल उत्तर का उपयोग करने के लिए ले जाता है, जब भी मुझे ऑटोसाइज़िंग कोशिकाओं की आवश्यकता नहीं होती है।

class LeftAlignedFlowLayout: UICollectionViewFlowLayout {

    private override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? {
        let layoutAttribute = super.layoutAttributesForItemAtIndexPath(indexPath)?.copy() as? UICollectionViewLayoutAttributes

        // First in a row.
        if layoutAttribute?.frame.origin.x == sectionInset.left {
            return layoutAttribute
        }

        // We need to align it to the previous item.
        let previousIndexPath = NSIndexPath(forItem: indexPath.item - 1, inSection: indexPath.section)
        guard let previousLayoutAttribute = self.layoutAttributesForItemAtIndexPath(previousIndexPath) else {
            return layoutAttribute
        }

        layoutAttribute?.frame.origin.x = previousLayoutAttribute.frame.maxX + self.minimumInteritemSpacing

        return layoutAttribute
    }
}

यह पहले खंड के लिए काम करता है, हालांकि लेबल स्क्रॉल होने तक दूसरे खंड पर लेबल नहीं बदलता है। मेरा संग्रह दृश्य तालिका सेल में है।
ईआई कैप्टन v2.0

5

स्विफ्ट में। माइकल्स जवाब के अनुसार

override func layoutAttributesForElementsInRect(rect: CGRect) ->     [UICollectionViewLayoutAttributes]? {
    guard let oldAttributes = super.layoutAttributesForElementsInRect(rect) else {
        return super.layoutAttributesForElementsInRect(rect)
    }
    let spacing = CGFloat(50) // REPLACE WITH WHAT SPACING YOU NEED
    var newAttributes = [UICollectionViewLayoutAttributes]()
    var leftMargin = self.sectionInset.left
    for attributes in oldAttributes {
        if (attributes.frame.origin.x == self.sectionInset.left) {
            leftMargin = self.sectionInset.left
        } else {
            var newLeftAlignedFrame = attributes.frame
            newLeftAlignedFrame.origin.x = leftMargin
            attributes.frame = newLeftAlignedFrame
        }

        leftMargin += attributes.frame.width + spacing
        newAttributes.append(attributes)
    }
    return newAttributes
}

4

सभी उत्तरों के आधार पर, मैं थोड़ा बदलता हूं और यह मेरे लिए अच्छा काम करता है

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    let attributes = super.layoutAttributesForElements(in: rect)

    var leftMargin = sectionInset.left
    var maxY: CGFloat = -1.0


    attributes?.forEach { layoutAttribute in
        if layoutAttribute.frame.origin.y >= maxY
                   || layoutAttribute.frame.origin.x == sectionInset.left {
            leftMargin = sectionInset.left
        }

        if layoutAttribute.frame.origin.x == sectionInset.left {
            leftMargin = sectionInset.left
        }
        else {
            layoutAttribute.frame.origin.x = leftMargin
        }

        leftMargin += layoutAttribute.frame.width
        maxY = max(layoutAttribute.frame.maxY, maxY)
    }

    return attributes
}

4

यदि आप में से किसी को भी समस्या का सामना करना पड़ रहा है - संग्रह के दृश्य के दाईं ओर संग्रह की दृष्टि से दाईं ओर स्थित कुछ कक्ष । तो कृपया इस का उपयोग करें -

class CustomCollectionViewFlowLayout: UICollectionViewFlowLayout {

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let attributes = super.layoutAttributesForElements(in: rect)

        var leftMargin : CGFloat = sectionInset.left
        var maxY: CGFloat = -1.0
        attributes?.forEach { layoutAttribute in
            if Int(layoutAttribute.frame.origin.y) >= Int(maxY) {
                leftMargin = sectionInset.left
            }

            layoutAttribute.frame.origin.x = leftMargin

            leftMargin += layoutAttribute.frame.width + minimumInteritemSpacing
            maxY = max(layoutAttribute.frame.maxY , maxY)
        }
        return attributes
    }
}

CGFloat मानों की तुलना करने के स्थान पर INT का उपयोग करें ।


3

जब आपके संग्रह दृश्य को हेडर या फ़ुटर भी मिल जाता है, तो उत्तर के आधार पर, लेकिन निश्चित क्रैश और संरेखित समस्याएं। बाईं ओर केवल कोशिकाओं को संरेखित करना:

class LeftAlignedCollectionViewFlowLayout: UICollectionViewFlowLayout {

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let attributes = super.layoutAttributesForElements(in: rect)

        var leftMargin = sectionInset.left
        var prevMaxY: CGFloat = -1.0
        attributes?.forEach { layoutAttribute in

            guard layoutAttribute.representedElementCategory == .cell else {
                return
            }

            if layoutAttribute.frame.origin.y >= prevMaxY {
                leftMargin = sectionInset.left
            }

            layoutAttribute.frame.origin.x = leftMargin

            leftMargin += layoutAttribute.frame.width + minimumInteritemSpacing
            prevMaxY = layoutAttribute.frame.maxY
        }

        return attributes
    }
}

2

माइकल सैंड के जवाब के लिए धन्यवाद । मैंने इसे कई पंक्तियों (प्रत्येक पंक्ति के समान संरेखण शीर्ष y) के समाधान के लिए संशोधित किया है जो कि वाम संरेखण है, यहां तक ​​कि प्रत्येक आइटम के लिए रिक्ति।

static CGFloat const ITEM_SPACING = 10.0f;

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    CGRect contentRect = {CGPointZero, self.collectionViewContentSize};

    NSArray *attributesForElementsInRect = [super layoutAttributesForElementsInRect:contentRect];
    NSMutableArray *newAttributesForElementsInRect = [[NSMutableArray alloc] initWithCapacity:attributesForElementsInRect.count];

    CGFloat leftMargin = self.sectionInset.left; //initalized to silence compiler, and actaully safer, but not planning to use.
    NSMutableDictionary *leftMarginDictionary = [[NSMutableDictionary alloc] init];

    for (UICollectionViewLayoutAttributes *attributes in attributesForElementsInRect) {
        UICollectionViewLayoutAttributes *attr = attributes.copy;

        CGFloat lastLeftMargin = [[leftMarginDictionary valueForKey:[[NSNumber numberWithFloat:attributes.frame.origin.y] stringValue]] floatValue];
        if (lastLeftMargin == 0) lastLeftMargin = leftMargin;

        CGRect newLeftAlignedFrame = attr.frame;
        newLeftAlignedFrame.origin.x = lastLeftMargin;
        attr.frame = newLeftAlignedFrame;

        lastLeftMargin += attr.frame.size.width + ITEM_SPACING;
        [leftMarginDictionary setObject:@(lastLeftMargin) forKey:[[NSNumber numberWithFloat:attributes.frame.origin.y] stringValue]];
        [newAttributesForElementsInRect addObject:attr];
    }

    return newAttributesForElementsInRect;
}

1

यहां स्विफ्ट 5 के साथ काम करने वाले सबसे अच्छे कोड को खोजने की मेरी यात्रा है। मैंने चेतावनी और मुद्दों का हल करने के लिए इस थ्रेड और कुछ अन्य थ्रेड्स में से कुछ उत्तर जोड़े हैं। मेरे संग्रह दृश्य के माध्यम से स्क्रॉल करने पर मुझे एक चेतावनी और कुछ असामान्य व्यवहार हुआ। कंसोल निम्न प्रिंट करता है:

ऐसा होने की संभावना है क्योंकि प्रवाह लेआउट "xyz" UICollectionViewFlowLayout द्वारा उन्हें कॉपी किए बिना विशेषताओं को संशोधित कर रहा है।

मेरे सामने एक और मुद्दा यह है कि कुछ लंबी कोशिकाओं को स्क्रीन के दाईं ओर क्रॉप किया जा रहा है। इसके अलावा, मैं अनुभाग इनसेट्स और प्रतिनिधि कार्यों में न्यूनतमInteritemSpacing सेट कर रहा था जिसके परिणामस्वरूप मूल्यों को कस्टम वर्ग में प्रतिबिंबित नहीं किया गया था। मेरे संग्रह दृश्य पर लागू होने से पहले लेआउट के उदाहरण में उन विशेषताओं को निर्धारित किया गया था।

यहां बताया गया है कि मैंने अपने संग्रह दृश्य के लिए लेआउट का उपयोग कैसे किया:

let layout = LeftAlignedCollectionViewFlowLayout()
layout.minimumInteritemSpacing = 5
layout.minimumLineSpacing = 7.5
layout.sectionInset = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
super.init(frame: frame, collectionViewLayout: layout)

यहाँ प्रवाह लेआउट वर्ग है

class LeftAlignedCollectionViewFlowLayout: UICollectionViewFlowLayout {

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let attributes = super.layoutAttributesForElements(in: rect)?.map { $0.copy() as! UICollectionViewLayoutAttributes }

        var leftMargin = sectionInset.left
        var maxY: CGFloat = -1.0
        attributes?.forEach { layoutAttribute in
            guard layoutAttribute.representedElementCategory == .cell else {
                return
            }

            if Int(layoutAttribute.frame.origin.y) >= Int(maxY) || layoutAttribute.frame.origin.x == sectionInset.left {
                leftMargin = sectionInset.left
            }

            if layoutAttribute.frame.origin.x == sectionInset.left {
                leftMargin = sectionInset.left
            }
            else {
                layoutAttribute.frame.origin.x = leftMargin
            }

            leftMargin += layoutAttribute.frame.width + minimumInteritemSpacing
            maxY = max(layoutAttribute.frame.maxY , maxY)
        }

        return attributes
    }
}

आपने मेरा दिन बचाया
डेविड 'mArm' Ansermot

0

UICollectionView के साथ समस्या यह है कि यह स्वचालित रूप से उपलब्ध क्षेत्र में कोशिकाओं को फिट करने की कोशिश करता है। मैंने पहले पंक्तियों और स्तंभों की संख्या को परिभाषित करके और फिर उस पंक्ति और स्तंभ के लिए सेल आकार को परिभाषित करके किया है

1) मेरे UICollectionView के वर्गों (पंक्तियों) को परिभाषित करने के लिए:

(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView

2) एक अनुभाग में वस्तुओं की संख्या को परिभाषित करने के लिए। आप हर अनुभाग के लिए विभिन्न मदों को परिभाषित कर सकते हैं। आप 'सेक्शन' पैरामीटर का उपयोग करके सेक्शन नंबर प्राप्त कर सकते हैं।

(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section

3) प्रत्येक खंड और पंक्ति के लिए सेल आकार को अलग-अलग परिभाषित करना। आप खंड संख्या और 'indexPath' पैरामीटर यानी का उपयोग कर पंक्ति संख्या प्राप्त कर सकते हैं [indexPath section]अनुभाग नंबर के लिए और [indexPath row]पंक्ति संख्या के लिए।

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

4) तब आप अपनी कोशिकाओं को पंक्तियों और वर्गों में प्रदर्शित कर सकते हैं:

(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath

नोट: UICollectionView में

Section == Row
IndexPath.Row == Column

0

माइक सैंड का जवाब अच्छा है, लेकिन मैंने इस कोड के साथ कुछ मुद्दों का अनुभव किया था (जैसे लंबी सेल बाहर निकल गई)। और नया कोड:

#define ITEM_SPACE 7.0f

@implementation LeftAlignedCollectionViewFlowLayout
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSArray* attributesToReturn = [super layoutAttributesForElementsInRect:rect];
    for (UICollectionViewLayoutAttributes* attributes in attributesToReturn) {
        if (nil == attributes.representedElementKind) {
            NSIndexPath* indexPath = attributes.indexPath;
            attributes.frame = [self layoutAttributesForItemAtIndexPath:indexPath].frame;
        }
    }
    return attributesToReturn;
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewLayoutAttributes* currentItemAttributes =
    [super layoutAttributesForItemAtIndexPath:indexPath];

    UIEdgeInsets sectionInset = [(UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout sectionInset];

    if (indexPath.item == 0) { // first item of section
        CGRect frame = currentItemAttributes.frame;
        frame.origin.x = sectionInset.left; // first item of the section should always be left aligned
        currentItemAttributes.frame = frame;

        return currentItemAttributes;
    }

    NSIndexPath* previousIndexPath = [NSIndexPath indexPathForItem:indexPath.item-1 inSection:indexPath.section];
    CGRect previousFrame = [self layoutAttributesForItemAtIndexPath:previousIndexPath].frame;
    CGFloat previousFrameRightPoint = previousFrame.origin.x + previousFrame.size.width + ITEM_SPACE;

    CGRect currentFrame = currentItemAttributes.frame;
    CGRect strecthedCurrentFrame = CGRectMake(0,
                                              currentFrame.origin.y,
                                              self.collectionView.frame.size.width,
                                              currentFrame.size.height);

    if (!CGRectIntersectsRect(previousFrame, strecthedCurrentFrame)) { // if current item is the first item on the line
        // the approach here is to take the current frame, left align it to the edge of the view
        // then stretch it the width of the collection view, if it intersects with the previous frame then that means it
        // is on the same line, otherwise it is on it's own new line
        CGRect frame = currentItemAttributes.frame;
        frame.origin.x = sectionInset.left; // first item on the line should always be left aligned
        currentItemAttributes.frame = frame;
        return currentItemAttributes;
    }

    CGRect frame = currentItemAttributes.frame;
    frame.origin.x = previousFrameRightPoint;
    currentItemAttributes.frame = frame;
    return currentItemAttributes;
}

0

अगर यह इसे लागू करता है, तो minimumInteritemSpacingप्रतिनिधिमंडल से सम्मान के लिए एंजेल गार्सिया ओलोक्वी का जवाब संपादित collectionView(_:layout:minimumInteritemSpacingForSectionAt:)किया गया।

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    let attributes = super.layoutAttributesForElements(in: rect)

    var leftMargin = sectionInset.left
    var maxY: CGFloat = -1.0
    attributes?.forEach { layoutAttribute in
        if layoutAttribute.frame.origin.y >= maxY {
            leftMargin = sectionInset.left
        }

        layoutAttribute.frame.origin.x = leftMargin

        let delegate = collectionView?.delegate as? UICollectionViewDelegateFlowLayout
        let spacing = delegate?.collectionView?(collectionView!, layout: self, minimumInteritemSpacingForSectionAt: 0) ?? minimumInteritemSpacing

        leftMargin += layoutAttribute.frame.width + spacing
        maxY = max(layoutAttribute.frame.maxY , maxY)
    }

    return attributes
}

0

उपरोक्त कोड मेरे लिए काम करता है। मैं संबंधित स्विफ्ट 3.0 कोड साझा करना चाहूंगा।

class SFFlowLayout: UICollectionViewFlowLayout {

    let itemSpacing: CGFloat = 3.0

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {

        let attriuteElementsInRect = super.layoutAttributesForElements(in: rect)
        var newAttributeForElement: Array<UICollectionViewLayoutAttributes> = []
        var leftMargin = self.sectionInset.left
        for tempAttribute in attriuteElementsInRect! {
            let attribute = tempAttribute 
            if attribute.frame.origin.x == self.sectionInset.left {
                leftMargin = self.sectionInset.left
            }
            else {
                var newLeftAlignedFrame = attribute.frame
                newLeftAlignedFrame.origin.x = leftMargin
                attribute.frame = newLeftAlignedFrame
            }
            leftMargin += attribute.frame.size.width + itemSpacing
            newAttributeForElement.append(attribute)
        }
        return newAttributeForElement
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.