UICollectionView की कोशिकाओं को केंद्र में कैसे संरेखित करें?


99

मैं वर्तमान UICollectionViewमें यूजर इंटरफेस ग्रिड के लिए उपयोग कर रहा हूं , और यह ठीक काम करता है। हालाँकि, मैं क्षैतिज स्क्रॉलिंग सक्षम करना चाहूंगा। ग्रिड प्रति पृष्ठ 8 आइटम का समर्थन करता है और जब आइटम की कुल संख्या 4 होती है, तो 4 कहें, इस तरह से आइटम को क्षैतिज दिशा के साथ व्यवस्थित किया जाना चाहिए:

0 0 x x
0 0 x x

यहां 0 -> संग्रह आइटम और x -> रिक्त कक्ष

वहाँ उन्हें केंद्र की तरह बनाने के लिए एक तरीका है:

x 0 0 x
x 0 0 x

ताकि सामग्री अधिक साफ दिखे?

इसके अलावा नीचे की व्यवस्था भी एक समाधान हो सकता है जिसकी मैं अपेक्षा कर रहा हूं।

0 0 0 0
x x x x

जवाबों:


80

मुझे लगता है कि आप कुछ इस तरह से लागू करके सिंगल लाइन लुक हासिल कर सकते हैं:

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    return UIEdgeInsetsMake(0, 100, 0, 0);
}

आपको उस संख्या के साथ चारों ओर खेलना होगा ताकि यह पता लगाया जा सके कि सामग्री को एक पंक्ति में कैसे लागू किया जाए। पहला 0, शीर्ष एज तर्क है, आप उस एक को भी समायोजित कर सकते हैं, यदि आप स्क्रीन में सामग्री को लंबवत रूप से केंद्रित करना चाहते हैं।


1
यह अच्छा समाधान धन्यवाद है, हालांकि इसके लिए मेरी तरफ से कुछ अतिरिक्त गणनाओं की आवश्यकता है।
आरवीएन

आप इन मूल्यों की गणना कैसे करते हैं?
jjxtra

7
इनसेट्स को गतिशील रूप से परिकलित करने के लिए: CGFloat leftInset = (collectionView.frame.size.width-40 * [collectionView numberOfItemsInSection: अनुभाग]) / 2; 40 = कोशिका का आकार
अब्दुलियम रहमानियस

1
@AbduliamRehmanius लेकिन यह मानता है कि कोशिकाएँ क्षैतिज रूप से नहीं हैं। आमतौर पर वे होते हैं। और यह वास्तविक रिक्त स्थान निर्धारित करने के लिए अस्थिर लगता है क्योंकि minimumInteritemSpacingकेवल उनके न्यूनतम इंगित करता है।
Drux

5
यह वास्तव में होना चाहिए return UIEdgeInsetsMake(0, 100, 0, 100);। यदि अतिरिक्त स्थान है, तो संग्रह दृश्य अंतरिम रिक्ति का विस्तार करेगा, इसलिए आपको सुनिश्चित करना होगा कि LeftInset + CellWidth * Ncells + CellSpacing * (Ncells-1) + RightInset = CollectionViewWidth
vish

82

केंद्र-संरेखित, गतिशील-चौड़ाई संग्रह कोशिकाओं के समाधान की तलाश करने वालों के लिए , जैसा कि मैं था, मैंने केंद्र के लिए केंद्र-संरेखित उपवर्ग बनाने के लिए बाएं-संरेखित संस्करण के लिए एन्जिल के उत्तर को संशोधित किया UICollectionViewFlowLayout

CenterAlignedCollectionViewFlowLayout

// NOTE: Doesn't work for horizontal layout!
class CenterAlignedCollectionViewFlowLayout: UICollectionViewFlowLayout {
    
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        guard let superAttributes = super.layoutAttributesForElements(in: rect) else { return nil }
        // Copy each item to prevent "UICollectionViewFlowLayout has cached frame mismatch" warning
        guard let attributes = NSArray(array: superAttributes, copyItems: true) as? [UICollectionViewLayoutAttributes] else { return nil }
        
        // Constants
        let leftPadding: CGFloat = 8
        let interItemSpacing = minimumInteritemSpacing
        
        // Tracking values
        var leftMargin: CGFloat = leftPadding // Modified to determine origin.x for each item
        var maxY: CGFloat = -1.0 // Modified to determine origin.y for each item
        var rowSizes: [[CGFloat]] = [] // Tracks the starting and ending x-values for the first and last item in the row
        var currentRow: Int = 0 // Tracks the current row
        attributes.forEach { layoutAttribute in
            
            // Each layoutAttribute represents its own item
            if layoutAttribute.frame.origin.y >= maxY {
                
                // This layoutAttribute represents the left-most item in the row
                leftMargin = leftPadding
                
                // Register its origin.x in rowSizes for use later
                if rowSizes.count == 0 {
                    // Add to first row
                    rowSizes = [[leftMargin, 0]]
                } else {
                    // Append a new row
                    rowSizes.append([leftMargin, 0])
                    currentRow += 1
                }
            }
            
            layoutAttribute.frame.origin.x = leftMargin
            
            leftMargin += layoutAttribute.frame.width + interItemSpacing
            maxY = max(layoutAttribute.frame.maxY, maxY)
            
            // Add right-most x value for last item in the row
            rowSizes[currentRow][1] = leftMargin - interItemSpacing
        }
        
        // At this point, all cells are left aligned
        // Reset tracking values and add extra left padding to center align entire row
        leftMargin = leftPadding
        maxY = -1.0
        currentRow = 0
        attributes.forEach { layoutAttribute in
            
            // Each layoutAttribute is its own item
            if layoutAttribute.frame.origin.y >= maxY {
                
                // This layoutAttribute represents the left-most item in the row
                leftMargin = leftPadding
                
                // Need to bump it up by an appended margin
                let rowWidth = rowSizes[currentRow][1] - rowSizes[currentRow][0] // last.x - first.x
                let appendedMargin = (collectionView!.frame.width - leftPadding  - rowWidth - leftPadding) / 2
                leftMargin += appendedMargin
                
                currentRow += 1
            }
            
            layoutAttribute.frame.origin.x = leftMargin
            
            leftMargin += layoutAttribute.frame.width + interItemSpacing
            maxY = max(layoutAttribute.frame.maxY, maxY)
        }
        
        return attributes
    }
}

CenterAlignedCollectionViewFlowLayout


3
इसने निम्नलिखित चेतावनी दी, हालांकि यह होने की संभावना है क्योंकि फ्लो लेआउट उपवर्ग xxxx.CustomCollectionViewFlowLayout विशेषताओं को संशोधित कर रहा है UICollectionViewFlowLayout द्वारा उन्हें सही करने के लिए कॉपी किए बिना लौटाया गया है, मैंने कोड का उपयोग किया है [ stackoverflow.com/a/36315664/1067951] से guard let superArray = super.layoutAttributesForElementsInRect(rect) else { return nil } guard let attributes = NSArray(array: superArray, copyItems: true) as? [UICollectionViewLayoutAttributes] else { return nil }
Ram

प्रविष्टि के लिए धन्यवाद। इसे हासिल करने की कोशिश में कुछ दिन बिताए!
मई

नौकरी के लिए और समुदाय के साथ परिणाम साझा करने के लिए धन्यवाद। मैंने कोड अपडेट किया। सबसे पहले, मैंने @Ram द्वारा अनुशंसित परिवर्तन जोड़े। दूसरा, मैं interItemSpacingडिफ़ॉल्ट का उपयोग करने के लिए बदलता हूं minimumInteritemSpacing
केलीन

@ राम मेरे पास डिबगर में इसे पकड़ने के लिए UICollectionViewFlowLayoutBreakForInvalidSizes में एक प्रतीकात्मक विराम बिंदु है। UICollectionViewFlowLayout के व्यवहार को परिभाषित नहीं किया गया है: क्योंकि आइटम की चौड़ाई UICollectionView की चौड़ाई से कम होनी चाहिए और इनसेट्स बाएँ और दाएँ मानों को घटाता है, माइनस इनसेट्स को बाएँ और दाएँ मान
EI Captain v2.0

1
@ इस तरह का उपयोग viewDidLoad () में करें। collectionViewName.collectionViewLayout = CenterAlignedCollectionViewFlowLayout ()
मितेश दोबरीया

57

यहाँ शीर्ष समाधान मेरे लिए आउट-ऑफ-द-बॉक्स काम नहीं करते थे, इसलिए मैं इस के साथ आया जो प्रवाह लेआउट और केवल एक खंड के साथ किसी भी क्षैतिज स्क्रॉल संग्रह दृश्य के लिए काम करना चाहिए:

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
    {
    // Add inset to the collection view if there are not enough cells to fill the width.
    CGFloat cellSpacing = ((UICollectionViewFlowLayout *) collectionViewLayout).minimumLineSpacing;
    CGFloat cellWidth = ((UICollectionViewFlowLayout *) collectionViewLayout).itemSize.width;
    NSInteger cellCount = [collectionView numberOfItemsInSection:section];
    CGFloat inset = (collectionView.bounds.size.width - (cellCount * cellWidth) - ((cellCount - 1)*cellSpacing)) * 0.5;
    inset = MAX(inset, 0.0);
    return UIEdgeInsetsMake(0.0, inset, 0.0, 0.0);
    }

आपको 'सेलकाउंट - 1' द्वारा सेलस्पेशिंग गुणा करना चाहिए और सेलकाउंट नहीं करना चाहिए। यह उस स्थिति में अधिक स्पष्ट हो जाता है जब केवल एक सेल होता है: कोशिकाओं के बीच कोई स्थान नहीं होता है।
फोबियो ओलिवेरा

और इनसेट = MAX (इनसेट, 0.0); लाइन। यह 'इनसेट = मैक्स (इनसेट, मिनिमम इनसेट);' जैसा दिखेगा। आपको उसी न्यूनतम इनसेट को दाईं ओर भी लागू करना चाहिए। संग्रह के दृश्य बहुत बेहतर लगते हैं जब वे किनारे तक सही बढ़ाते हैं :)
फैबियो ओलिवेरा

यदि सेल आकार स्थिर है, तो यह समाधान और @ सायन दोनों समान रूप से अच्छी तरह से काम करते हैं। क्या किसी को पता होगा कि कोशिकाओं का आकार कैसे प्राप्त करें? cellForItemAtIndexPath और दृश्यमान केवल जानकारी लौटाते हैं जब संग्रह दृश्यमान दिखाई देता है - और जीवनचक्र के इस बिंदु पर, यह नहीं है।
डैन लोफनी

@Siegfoult मैंने इसे लागू किया और यह ठीक काम नहीं किया मैंने बाईं ओर स्क्रॉल करने की कोशिश की यह मध्य में वापस आता है।
अनिरुद्ध महाले

34

इनसेट्स को गतिशील रूप से गणना करना आसान है, यह कोड हमेशा आपकी कोशिकाओं को केंद्र में रखेगा:

NSInteger const SMEPGiPadViewControllerCellWidth = 332;

...

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{

    NSInteger numberOfCells = self.view.frame.size.width / SMEPGiPadViewControllerCellWidth;
    NSInteger edgeInsets = (self.view.frame.size.width - (numberOfCells * SMEPGiPadViewControllerCellWidth)) / (numberOfCells + 1);

    return UIEdgeInsetsMake(0, edgeInsets, 0, edgeInsets);
}

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
    [self.collectionView.collectionViewLayout invalidateLayout];
}

4
आपका संशोधन क्या था?
सिरिस

4
SMEPGiPadViewControllerCellWidth के बजाय @Siriss आप CollectionViewLayout.itemSize. उपलब्धता का उपयोग कर सकते हैं, और यह संभवतः उनका संशोधन था
Michal Zaborowski

21

अन्य उत्तरों के समान, यह एक गतिशील उत्तर है जिसे स्थिर आकार की कोशिकाओं के लिए काम करना चाहिए। मैंने जो एक संशोधन किया, वह यह है कि मैंने दोनों तरफ पैडिंग लगाई। अगर मैंने ऐसा नहीं किया, तो मैंने समस्याओं का अनुभव किया।


उद्देश्य सी

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {

    NSInteger numberOfItems = [collectionView numberOfItemsInSection:section];
    CGFloat combinedItemWidth = (numberOfItems * collectionViewLayout.itemSize.width) + ((numberOfItems - 1) * collectionViewLayout.minimumInteritemSpacing);
    CGFloat padding = (collectionView.frame.size.width - combinedItemWidth) / 2;

    return UIEdgeInsetsMake(0, padding, 0, padding);
}

तीव्र

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
    let numberOfItems = CGFloat(collectionView.numberOfItems(inSection: section))
    let combinedItemWidth = (numberOfItems * flowLayout.itemSize.width) + ((numberOfItems - 1)  * flowLayout.minimumInteritemSpacing)
    let padding = (collectionView.frame.width - combinedItemWidth) / 2
    return UIEdgeInsets(top: 0, left: padding, bottom: 0, right: padding)
}

इसके अलावा, यदि आप अभी भी समस्याओं का सामना कर रहे हैं, तो सुनिश्चित करें कि आपने इन मूल्यों को परस्पर संबंधित प्रतीत होता है, दोनों को minimumInteritemSpacingऔर minimumLineSpacingसमान मानों को सेट किया है।

UICollectionViewFlowLayout *flowLayout = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;
flowLayout.minimumInteritemSpacing = 20.0;
flowLayout.minimumLineSpacing = 20.0;

बस मेरे लिए दुर्घटनाग्रस्त हो जाता है
सुपरटेककोबॉफ़ 11

ObjC ऑब्जेक्ट संग्रह में सीधे प्रयोग किया जाता है। यह UICollectionViewFlowLayout को आइटम तक पहुँचने में सक्षम होने के लिए और न्यूनतम InteritemSpacing करने के लिए सक्षम होना चाहिए
buttcmd

19

इसे अपने संग्रह दृश्य प्रतिनिधि में रखें। यह अन्य उत्तरों की तुलना में मूल प्रवाह लेआउट सेटिंग्स का अधिक विचार करता है और इस तरह अधिक सामान्य है।

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
    NSInteger cellCount = [collectionView.dataSource collectionView:collectionView numberOfItemsInSection:section];
    if( cellCount >0 )
    {
        CGFloat cellWidth = ((UICollectionViewFlowLayout*)collectionViewLayout).itemSize.width+((UICollectionViewFlowLayout*)collectionViewLayout).minimumInteritemSpacing;
        CGFloat totalCellWidth = cellWidth*cellCount + spacing*(cellCount-1);
        CGFloat contentWidth = collectionView.frame.size.width-collectionView.contentInset.left-collectionView.contentInset.right;
        if( totalCellWidth<contentWidth )
        {
            CGFloat padding = (contentWidth - totalCellWidth) / 2.0;
            return UIEdgeInsetsMake(0, padding, 0, padding);
        }
    }
    return UIEdgeInsetsZero;
}

स्विफ्ट संस्करण (धन्यवाद g0ld2k):

extension CommunityConnectViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {

    // Translated from Objective-C version at: http://stackoverflow.com/a/27656363/309736

        let cellCount = CGFloat(viewModel.getNumOfItemsInSection(0))

        if cellCount > 0 {
            let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
            let cellWidth = flowLayout.itemSize.width + flowLayout.minimumInteritemSpacing
            let totalCellWidth = cellWidth*cellCount + spacing*(cellCount-1)
            let contentWidth = collectionView.frame.size.width - collectionView.contentInset.left - collectionView.contentInset.right

            if (totalCellWidth < contentWidth) {
                let padding = (contentWidth - totalCellWidth) / 2.0
                return UIEdgeInsetsMake(0, padding, 0, padding)
            }
        }

        return UIEdgeInsetsZero
    }
}

3
वास्तव में आपके UICollectionViewDelegateFlowLayout में। धन्यवाद, यह कई कोशिकाओं के लिए काम करता है जो या तो एक पंक्ति या कई पंक्तियाँ हैं। कुछ अन्य उत्तर नहीं हैं।
जीन डे लिसा

2
इसे स्विफ्ट में बदल दिया और यह बहुत अच्छा काम करता है! यहाँ उपलब्ध स्विफ्ट संस्करण ।
g0ld2k

1
यह काफी सही नहीं है, totalCellWidthहोना चाहिए cellWidth*cellCount + spacing*(cellCount-1)
जेम्स पी

1
इनमें से कई "समाधानों" की कोशिश करने के बाद, यह एकमात्र ऐसा था जिसे मैं सही ढंग से काम करने में सक्षम था, इसे स्विफ्ट 3.0 के लिए थोड़ा संशोधित करने के बाद
केमिकोफा घोस्ट

@rugdealer क्या आप अपने स्विफ्ट 3 परिवर्तनों को प्रतिबिंबित करने के लिए उत्तर को संशोधित करना चाहते हैं?
बर्ट

11

स्टैटिक साइज़ कलेक्शन व्यू सेल्स के लिए मेरा सॉल्यूशन जो लेफ्ट और राईट पर पैडिंग करने की आवश्यकता है-

func collectionView(collectionView: UICollectionView, 
layout collectionViewLayout: UICollectionViewLayout, 
insetForSectionAtIndex section: Int) -> UIEdgeInsets {

    let flowLayout = (collectionViewLayout as! UICollectionViewFlowLayout)
    let cellSpacing = flowLayout.minimumInteritemSpacing
    let cellWidth = flowLayout.itemSize.width
    let cellCount = CGFloat(collectionView.numberOfItemsInSection(section))

    let collectionViewWidth = collectionView.bounds.size.width

    let totalCellWidth = cellCount * cellWidth
    let totalCellSpacing = cellSpacing * (cellCount - 1)

    let totalCellsWidth = totalCellWidth + totalCellSpacing

    let edgeInsets = (collectionViewWidth - totalCellsWidth) / 2.0

    return edgeInsets > 0 ? UIEdgeInsetsMake(0, edgeInsets, 0, edgeInsets) : UIEdgeInsetsMake(0, cellSpacing, 0, cellSpacing)
}

9

मेरे ऐप में एक टैग बार है जो UICollectionView& a का उपयोग करता हैUICollectionViewFlowLayout , , जिसमें सेल की एक पंक्ति संरेखित है।

सही इंडेंट पाने के लिए, आप अपनी चौड़ाई से सभी सेल (रिक्ति सहित) की कुल चौड़ाई घटाते हैं UICollectionView, और दो से विभाजित करते हैं।

[........Collection View.........]
[..Cell..][..Cell..]
                   [____indent___] / 2

=

[_____][..Cell..][..Cell..][_____]

समस्या यह है -

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;

पहले कहा जाता है ...

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

... तो आप कुल चौड़ाई निर्धारित करने के लिए अपनी कोशिकाओं पर पुनरावृति नहीं कर सकते।

इसके बजाय आपको फिर से प्रत्येक सेल की चौड़ाई की गणना करने की आवश्यकता है, मेरे मामले में मैं उपयोग [NSString sizeWithFont: ... ]करता हूं क्योंकि मेरे सेल की चौड़ाई यूआईबेल द्वारा ही निर्धारित की जाती है।

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
    CGFloat rightEdge = 0;
    CGFloat interItemSpacing = [(UICollectionViewFlowLayout*)collectionViewLayout minimumInteritemSpacing];

    for(NSString * tag in _tags)
        rightEdge += [tag sizeWithFont:[UIFont systemFontOfSize:14]].width+interItemSpacing;

    // To center the inter spacing too
    rightEdge -= interSpacing/2;

    // Calculate the inset
    CGFloat inset = collectionView.frame.size.width-rightEdge;

    // Only center align if the inset is greater than 0
    // That means that the total width of the cells is less than the width of the collection view and need to be aligned to the center.
    // Otherwise let them align left with no indent.

    if(inset > 0)
        return UIEdgeInsetsMake(0, inset/2, 0, 0);
    else
        return UIEdgeInsetsMake(0, 0, 0, 0);
}

आप कैसे प्राप्त करते हैं interSpacing?
Drux

interSpacingमेरे कोड में केवल एक स्थिरांक है, जो UICollectionViewCells
Siôn

1
लेकिन यह स्थान अलग-अलग हो सकता है: FWIK आप केवल न्यूनतम मूल्य मान / राज्य कर सकते हैं।
Drux

8

स्विफ्ट में, निम्नलिखित प्रत्येक कोशिका के किनारों पर पैडिंग की सही मात्रा को लागू करके समान रूप से कोशिकाओं को वितरित करेगा। बेशक, आपको पहले अपनी सेल की चौड़ाई जानने / सेट करने की आवश्यकता है।

func collectionView(collectionView: UICollectionView,
    layout collectionViewLayout: UICollectionViewLayout,
    insetForSectionAtIndex section: Int) -> UIEdgeInsets {

        var cellWidth : CGFloat = 110;

        var numberOfCells = floor(self.view.frame.size.width / cellWidth);
        var edgeInsets = (self.view.frame.size.width - (numberOfCells * cellWidth)) / (numberOfCells + 1);

        return UIEdgeInsetsMake(0, edgeInsets, 60.0, edgeInsets);
}

पंक्ति रिक्ति जोड़ने के लिए, 60.0 के बजाय 0 बदलें
ऑस्कर कास्टेलन

8

स्विफ्ट 2.0 मेरे लिए ठीक काम करता है!

 func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
        let edgeInsets = (screenWight - (CGFloat(elements.count) * 50) - (CGFloat(elements.count) * 10)) / 2
        return UIEdgeInsetsMake(0, edgeInsets, 0, 0);
    }

कहाँ पे: स्क्रीनवाइट : मूल रूप से मेरे संग्रह की चौड़ाई (पूर्ण स्क्रीन चौड़ाई) - मैंने लगातार बनाया: स्क्रीनवॉट: CGFloat = UIScreen.mainScreen ()। Bounds.width क्योंकि self.view.bounds हर बार 600 दिखाता है - SizeClasses तत्वों का coz -। कक्षों की संख्या 50 - मेरी मैनुअल सेल चौड़ाई 10 - कोशिकाओं के बीच मेरी दूरी


1
यदि आप UICollectionView का आकार बदलना चाहते हैं, तो आप ScreenWight के बजाय collectionView.frame.size. उपलब्धता का उपयोग कर सकते हैं
Oscar


2

निश्चित नहीं है कि यह Xcode 5 में नया है या नहीं, लेकिन अब आप इंटरफ़ेस बिल्डर के माध्यम से साइज़ इंस्पेक्टर को खोल सकते हैं और वहां एक इनसेट सेट कर सकते हैं। यह आपको आपके लिए ऐसा करने के लिए कस्टम कोड लिखने से रोकेगा और आपको उस गति को बढ़ाना चाहिए जिस पर आप उचित ऑफ़सेट पाते हैं।


1

ऐसा करने का एक और तरीका है collectionView.center.x, जैसे:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    if let
        collectionView = collectionView,
        layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
    {
        collectionView.center.x = view.center.x + layout.sectionInset.right / 2.0
    }
}

इस मामले में, केवल सही इनसेट का सम्मान करना जो मेरे लिए काम करता है।


1

User3676011 उत्तर के आधार पर, मैं छोटे सुधार के साथ अधिक विस्तृत सुझाव दे सकता हूं। यह समाधान स्विफ्ट 2.0 पर बहुत अच्छा काम करता है ।

enum CollectionViewContentPosition {
    case Left
    case Center
}

var collectionViewContentPosition: CollectionViewContentPosition = .Left

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout,
    insetForSectionAtIndex section: Int) -> UIEdgeInsets {

    if collectionViewContentPosition == .Left {
        return UIEdgeInsetsZero
    }

    // Center collectionView content

    let itemsCount: CGFloat = CGFloat(collectionView.numberOfItemsInSection(section))
    let collectionViewWidth: CGFloat = collectionView.bounds.width

    let itemWidth: CGFloat = 40.0
    let itemsMargin: CGFloat = 10.0

    let edgeInsets = (collectionViewWidth - (itemsCount * itemWidth) - ((itemsCount-1) * itemsMargin)) / 2

    return UIEdgeInsetsMake(0, edgeInsets, 0, 0)
}

में एक मुद्दा था

(CGFloat (एलिमेंट्स.काउंट) * 10))

अतिरिक्त -1उल्लेख कहां होना चाहिए ।


1

इस तरह से मुझे एक संग्रह दृश्य प्राप्त हुआ जो एक निश्चित इंटरमिटेम रिक्ति के साथ केंद्र में था

#define maxInteritemSpacing 6
#define minLineSpacing 3

@interface MyFlowLayout()<UICollectionViewDelegateFlowLayout>

@end

@implementation MyFlowLayout

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.minimumInteritemSpacing = 3;
        self.minimumLineSpacing = minLineSpacing;
        self.scrollDirection = UICollectionViewScrollDirectionVertical;
    }
    return self;
}

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

    if (answer.count > 0) {
        NSMutableArray<NSMutableArray<UICollectionViewLayoutAttributes *> *> *rows = [NSMutableArray array];
        CGFloat maxY = -1.0f;
        NSInteger currentRow = 0;

        //add first item to row and set its maxY
        [rows addObject:[@[answer[0]] mutableCopy]];
        maxY = CGRectGetMaxY(((UICollectionViewLayoutAttributes *)answer[0]).frame);

        for(int i = 1; i < [answer count]; ++i) {
            //handle maximum spacing
            UICollectionViewLayoutAttributes *currentLayoutAttributes = answer[i];
            UICollectionViewLayoutAttributes *prevLayoutAttributes = answer[i - 1];
            NSInteger maximumSpacing = maxInteritemSpacing;
            NSInteger origin = CGRectGetMaxX(prevLayoutAttributes.frame);

            if(origin + maximumSpacing + currentLayoutAttributes.frame.size.width < self.collectionViewContentSize.width) {
                CGRect frame = currentLayoutAttributes.frame;
                frame.origin.x = origin + maximumSpacing;
                currentLayoutAttributes.frame = frame;
            }

            //handle center align
            CGFloat currentY = currentLayoutAttributes.frame.origin.y;
            if (currentY >= maxY) {
                [self shiftRowToCenterForCurrentRow:rows[currentRow]];

                //next row
                [rows addObject:[@[currentLayoutAttributes] mutableCopy]];
                currentRow++;
            }
            else {
                //same row
                [rows[currentRow] addObject:currentLayoutAttributes];
            }

            maxY = MAX(CGRectGetMaxY(currentLayoutAttributes.frame), maxY);
        }

        //mark sure to shift 1 row items
        if (currentRow == 0) {
            [self shiftRowToCenterForCurrentRow:rows[currentRow]];
        }
    }

    return answer;
}

- (void)shiftRowToCenterForCurrentRow:(NSMutableArray<UICollectionViewLayoutAttributes *> *)currentRow
{
    //shift row to center
    CGFloat endingX = CGRectGetMaxX(currentRow.lastObject.frame);
    CGFloat shiftX = (self.collectionViewContentSize.width - endingX) / 2.f;
    for (UICollectionViewLayoutAttributes *attr in currentRow) {
        CGRect shiftedFrame = attr.frame;
        shiftedFrame.origin.x += shiftX;
        attr.frame = shiftedFrame;
    }
}

@end

1

स्विफ्ट 3.0 का उपयोग करके किग्राडिस के उद्देश्य सी उत्तर का कार्य संस्करण:

let flow = UICollectionViewFlowLayout()

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {        
    let numberOfItems = collectionView.numberOfItems(inSection: 0)
    let combinedItemWidth:CGFloat = (CGFloat(numberOfItems) * flow.itemSize.width) + ((CGFloat(numberOfItems) - 1) * flow.minimumInteritemSpacing)
    let padding = (collectionView.frame.size.width - combinedItemWidth) / 2

    return UIEdgeInsetsMake(0, padding, 0, padding)
}

1

यहाँ कुछ मान्यताओं के साथ मेरा समाधान है:

  • केवल एक खंड है
  • बाएँ और दाएँ इनसेट समान हैं
  • सेल की ऊंचाई समान है

अपनी आवश्यकताओं को पूरा करने के लिए समायोजित करने के लिए स्वतंत्र महसूस करें।

चर सेल चौड़ाई के साथ केंद्रित लेआउट:

protocol HACenteredLayoutDelegate: UICollectionViewDataSource {
    func getCollectionView() -> UICollectionView
    func sizeOfCell(at index: IndexPath) -> CGSize
    func contentInsets() -> UIEdgeInsets
}

class HACenteredLayout: UICollectionViewFlowLayout {
    weak var delegate: HACenteredLayoutDelegate?
    private var cache = [UICollectionViewLayoutAttributes]()
    private var contentSize = CGSize.zero
    override var collectionViewContentSize: CGSize { return self.contentSize }

    required init(delegate: HACenteredLayoutDelegate) {
        self.delegate = delegate
        super.init()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func invalidateLayout() {
        cache.removeAll()
        super.invalidateLayout()
    }

    override func prepare() {
        if cache.isEmpty && self.delegate != nil && self.delegate!.collectionView(self.delegate!.getCollectionView(), numberOfItemsInSection: 0) > 0 {
            let insets = self.delegate?.contentInsets() ?? UIEdgeInsets.zero
            var rows: [(width: CGFloat, count: Int)] = [(0, 0)]
            let viewWidth: CGFloat = UIScreen.main.bounds.width
            var y = insets.top
            var unmodifiedIndexes = [IndexPath]()
            for itemNumber in 0 ..< self.delegate!.collectionView(self.delegate!.getCollectionView(), numberOfItemsInSection: 0) {
                let indexPath = IndexPath(item: itemNumber, section: 0)
                let cellSize = self.delegate!.sizeOfCell(at: indexPath)
                let potentialRowWidth = rows.last!.width + (rows.last!.count > 0 ? self.minimumInteritemSpacing : 0) + cellSize.width + insets.right + insets.left
                if potentialRowWidth > viewWidth {
                    let leftOverSpace = max((viewWidth - rows[rows.count - 1].width)/2, insets.left)
                    for i in unmodifiedIndexes {
                        self.cache[i.item].frame.origin.x += leftOverSpace
                    }
                    unmodifiedIndexes = []
                    rows.append((0, 0))
                    y += cellSize.height + self.minimumLineSpacing
                }
                unmodifiedIndexes.append(indexPath)
                let attribute = UICollectionViewLayoutAttributes(forCellWith: indexPath)
                rows[rows.count - 1].count += 1
                rows[rows.count - 1].width += rows[rows.count - 1].count > 1 ? self.minimumInteritemSpacing : 0
                attribute.frame = CGRect(x: rows[rows.count - 1].width, y: y, width: cellSize.width, height: cellSize.height)
                rows[rows.count - 1].width += cellSize.width
                cache.append(attribute)
            }
            let leftOverSpace = max((viewWidth - rows[rows.count - 1].width)/2, insets.left)
            for i in unmodifiedIndexes {
                self.cache[i.item].frame.origin.x += leftOverSpace
            }
            self.contentSize = CGSize(width: viewWidth, height: y + self.delegate!.sizeOfCell(at: IndexPath(item: 0, section: 0)).height + insets.bottom)
        }
    }

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

        for attributes in cache {
            if attributes.frame.intersects(rect) {
                layoutAttributes.append(attributes)
            }
        }
        return layoutAttributes
    }

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        if indexPath.item < self.cache.count {
            return self.cache[indexPath.item]
        }
        return nil
    }
}

परिणाम:

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


0

यहां बताया गया है कि आप इसे कैसे कर सकते हैं और यह ठीक काम करता है

func refreshCollectionView(_ count: Int) {
    let collectionViewHeight = collectionView.bounds.height
    let collectionViewWidth = collectionView.bounds.width
    let numberOfItemsThatCanInCollectionView = Int(collectionViewWidth / collectionViewHeight)
    if numberOfItemsThatCanInCollectionView > count {
        let totalCellWidth = collectionViewHeight * CGFloat(count)
        let totalSpacingWidth: CGFloat = CGFloat(count) * (CGFloat(count) - 1)
        // leftInset, rightInset are the global variables which I am passing to the below function
        leftInset = (collectionViewWidth - CGFloat(totalCellWidth + totalSpacingWidth)) / 2;
        rightInset = -leftInset
    } else {
        leftInset = 0.0
        rightInset = -collectionViewHeight
    }
    collectionView.reloadData()
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.