ইউআইকোলিকেশনভিউতে কক্ষগুলি বামে সারিবদ্ধ করুন


98

আমি আমার প্রকল্পে একটি ইউআইসিএল্লেশনভিউ ব্যবহার করছি, যেখানে একটি লাইনে বিভিন্ন বিস্তৃত প্রশস্ততার একাধিক কক্ষ রয়েছে। অনুসারে: https://developer.apple.com/library/content/docamentation/WindowsViews/ কনসেপ্টুয়াল / কালেকশনভিউ পিপোফোর্সআইওএস / ইউজিংথ্লো ফ্ল্যাট লেআউট / ইউসিংথফ্লোলয়আউট html

এটি সমান প্যাডিং সহ লাইন জুড়ে ঘরগুলি ছড়িয়ে দেয়। এটি প্রত্যাশার মতো ঘটেছিল, কেবলমাত্র আমি তাদের ন্যায্যতা বানাতে চাই না এবং হার্ড কোডিং একটি প্যাডিং প্রস্থ।

আমি অনুমান করি যে আমার ইউআইকোলিকেশনভিউফ্লোলয়আউট সাবক্লাস করা দরকার, তবে অনলাইনে টিউটোরিয়াল ইত্যাদি পড়ার পরে আমার মনে হয় না এটি কীভাবে কাজ করে।


উত্তর:


176

এই থ্রেডের অন্যান্য সমাধানগুলি সঠিকভাবে কাজ করে না, যখন লাইনটি কেবল 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 }
টিকিউইচুসয় আপনি

4
যেহেতু যেহেতু আমি যেমন কেন্দ্র-প্রান্তিক সংস্করণটি খুঁজছিলাম তাতে হোঁচট খেতে পেরেছে
অ্যালেক্স কোশি

4
এই সমাধানটি চেষ্টা করেও ইন্টারফেস বিল্ডার ইউটিলিটিস প্যানেলে সংগ্রহের ভিউয়ের সাথে লেআউটটি সংযুক্ত করতে পারেনি। কোড দ্বারা এটি শেষ। কোন সূত্র কেন?
একরপো

4
বাম-থেকে-ডান সিস্টেমে বামে এবং ডান-থেকে-বাম সিস্টেমগুলিতে ডানদিকে এই সারিবদ্ধকরণটি কীভাবে তৈরি করবেন?
রিক

4
ব্যবহারের জন্য এই সেলফ ক্লেকশন ভিউ.কোলেশনভিউলয়েআউট = বাম-সজ্জিত কালেকশনভিউফ্লোলয়আউট ()
ব্ল্যাকপস

64

এই প্রশ্নের উত্তরের সাথে অনেক দুর্দান্ত ধারণা অন্তর্ভুক্ত রয়েছে। তবে তাদের বেশিরভাগের কিছুটা ত্রুটি রয়েছে:

  • সলগুলির ওয়াইয়ের মান পরীক্ষা করে না এমন সমাধানগুলি কেবল একক-লাইন বিন্যাসের জন্য কাজ করে । তারা একাধিক লাইন সহ সংগ্রহ ভিউ লেআউটগুলির জন্য ব্যর্থ।
  • সলিউশন যে কি করতে পরীক্ষা Y মত মান দেবদূত গার্সিয়া Olloqui এর উত্তর কেবল কাজই যদি সব কোষ একই উচ্চতা আছে । তারা পরিবর্তনশীল উচ্চতা সহ কক্ষগুলির জন্য ব্যর্থ হয়।
  • সর্বাধিক সমাধানগুলি কেবল layoutAttributesForElements(in rect: CGRect)ফাংশনটিকে ওভাররাইড করে । তারা ওভাররাইড করে না layoutAttributesForItem(at indexPath: IndexPath)এটি একটি সমস্যা কারণ সংগ্রহ ভিউ পর্যালোচনা করে নির্দিষ্ট সূচক পাথের জন্য বিন্যাসের বৈশিষ্ট্যগুলি পুনরুদ্ধার করতে পরবর্তী ফাংশনটি কল করে। যদি আপনি সেই ফাংশন থেকে যথাযথ বৈশিষ্ট্যগুলি না ফেরান, আপনি সম্ভবত সমস্ত ধরণের ভিজ্যুয়াল বাগগুলিতে দৌড়াতে পারেন, উদাহরণস্বরূপ ঘরের সন্নিবেশ এবং মোছার অ্যানিমেশনগুলির সময় বা সংগ্রহ ভিউ বিন্যাসটি সেট করে সেল্ফ-সাইজিং সেলগুলি ব্যবহার করার সময় estimatedItemSizeঅ্যাপল ডক্স রাজ্য:

    প্রতিটি কাস্টম লেআউট অবজেক্টটি layoutAttributesForItemAtIndexPath:পদ্ধতিটি বাস্তবায়ন করবে বলে আশা করা হচ্ছে ।

  • অনেকগুলি সমাধান ফাংশনে rectপাস হওয়া প্যারামিটার সম্পর্কে অনুমানও layoutAttributesForElements(in rect: CGRect)করে। উদাহরণস্বরূপ, অনেকগুলি rectসর্বদা একটি নতুন লাইনের শুরুতে শুরু হয় এমন ধারনাটির উপর ভিত্তি করে যা অগত্যা ক্ষেত্রে হয় না।

সুতরাং অন্য কথায়:

এই পৃষ্ঠায় প্রস্তাবিত বেশিরভাগ সমাধান কিছু নির্দিষ্ট অ্যাপ্লিকেশনের জন্য কাজ করে তবে তারা প্রতিটি পরিস্থিতিতে প্রত্যাশার মতো কাজ করে না।


প্রান্তিককরণ সংগ্রহ ভিউফ্লোএলআউট

এই সমস্যাগুলি সমাধান করার জন্য আমি একটি UICollectionViewFlowLayoutসাবক্লাস তৈরি করেছি যা ম্যাট এবং ক্রিস ওয়াগনার তাদের অনুরূপ প্রশ্নের উত্তরে প্রস্তাবিত অনুরূপ ধারণা অনুসরণ করে । এটি হয় সেলগুলি সারিবদ্ধ করতে পারে

⬅︎ বাম :

বাম-সারিবদ্ধ লেআউট

বা ➡︎ ডান :

ডান-সারিবদ্ধ লেআউট

এবং অতিরিক্তভাবে তাদের নিজস্ব সারিগুলিতে ঘরগুলি উল্লম্বভাবে সারিবদ্ধ করার জন্য বিকল্পগুলি সরবরাহ করে (যদি তারা দৈর্ঘ্যে পৃথক হয়ে থাকে)।

আপনি কেবল এটি এখানে ডাউনলোড করতে পারেন:

https://github.com/mischa-hildebrand/ অ্যালাইন্টড কালেকশন ভিউফ্লোএলআউট

ব্যবহারটি সরাসরি-ফরওয়ার্ড এবং 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()ফাংশনটি সহজভাবে অ্যারেতে সমস্ত লেআউট বৈশিষ্ট্যের একটি গভীর অনুলিপি তৈরি করে its আপনি এর প্রয়োগের জন্য উত্স কোডটি দেখতে পারেন ))

সুতরাং এখন আমাদের কেবলমাত্র কাজটি layoutAttributesForItem(at indexPath: IndexPath)সঠিকভাবে কার্যকর করা। সুপার ক্লাস UICollectionViewFlowLayoutইতিমধ্যে প্রতিটি লাইনে সঠিক সংখ্যক কক্ষ রেখে দেয় যাতে আমাদের কেবল তাদের নিজ নিজ সারির মধ্যে রেখে যেতে হবে। আমাদের প্রতিটি ঘরকে বামে স্থানান্তর করতে প্রয়োজনীয় পরিমাণের পরিমাণ গণনা করতে অসুবিধা রয়েছে।

যেহেতু আমরা কোষগুলির মধ্যে একটি নির্দিষ্ট ব্যবধান রাখতে চাই মূল ধারণাটি কেবল ধরে নেওয়া উচিত যে পূর্ববর্তী ঘরটি (বর্তমানে নির্ধারিত কোষের বাম ঘরটি) ইতিমধ্যে সঠিকভাবে অবস্থিত। তারপরে আমাদের কেবল maxXপূর্ববর্তী কক্ষের ফ্রেমের মানের সাথে ঘর ব্যবধান যুক্ত করতে হবে এবং origin.xএটি বর্তমান কক্ষের ফ্রেমের মান।

এখন আমাদের কেবল তখনই জানতে হবে যে আমরা কখন একটি লাইনের শুরুতে পৌঁছেছি, যাতে আমরা আগের লাইনের একটি ঘরের পাশের একটি ঘরটি সারিবদ্ধ না করি। (এটি কেবলমাত্র একটি ভুল লেআউটই তৈরি করবে না তবে এটি চূড়ান্তভাবে পিছিয়েও থাকবে be) সুতরাং আমাদের পুনরাবৃত্তি অ্যাঙ্কর থাকা দরকার। পুনরাবৃত্তি অ্যাঙ্করটি সন্ধান করার জন্য আমি যে পদ্ধতিটি ব্যবহার করি তা নিম্নলিখিত:

আমি সূচী i তে কোষটি সূচী i-1 সহকারে একই লাইনে আছে কিনা তা জানতে ...

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

... আমি বর্তমান কক্ষের চারপাশে একটি আয়তক্ষেত্র "আঁকুন" এবং পুরো সংগ্রহ দর্শনের প্রস্থের উপরে প্রসারিত করি। UICollectionViewFlowLayoutকেন্দ্রগুলি হিসাবে একই কক্ষের সমস্ত ঘর উল্লম্বভাবে প্রতিটি কক্ষকে অবশ্যই এই আয়তক্ষেত্রটি ছেদ করতে হবে

সুতরাং, আমি সহজেই পরীক্ষা করে দেখি যে সূচী i-1 সহ ঘরটি সূচি i দিয়ে ঘর থেকে তৈরি এই লাইন আয়তক্ষেত্রের সাথে ছেদ করে কিনা ।

  • যদি এটি ছেদ করে তবে, সূচী i সহ ঘরটি লাইনের সবচেয়ে বাম কোষ নয়।
    Cell পূর্ববর্তী কক্ষের ফ্রেম পান (সূচী i − 1 সহ ) এবং বর্তমান ঘরটি এর পাশেই সরিয়ে নিন।

  • যদি এটি ছেদ না করে তবে সূচক i সহ ঘরটি লাইনের বামে সবচেয়ে বেশি সেল হয়।
    Cell ঘরটি সংগ্রহের ভিউয়ের বাম প্রান্তে সরান (তার উল্লম্ব অবস্থানটি পরিবর্তন না করে)।

আমি layoutAttributesForItem(at indexPath: IndexPath)এখানে ফাংশনের আসল বাস্তবায়ন পোস্ট করব না কারণ আমি মনে করি সবচেয়ে গুরুত্বপূর্ণ অংশটি ধারণাটি বোঝার জন্য এবং আপনি সর্বদা উত্স কোডটিতে আমার প্রয়োগ পরীক্ষা করতে পারেন । (এটি এখানে .rightবর্ণিত চেয়ে কিছুটা জটিল কারণ আমি প্রান্তিককরণ এবং বিভিন্ন উল্লম্ব সারিবদ্ধ বিকল্পগুলিও অনুমতি দিই । তবে এটি একই ধারণা অনুসরণ করে))


বাহ, আমি মনে করি এটি স্ট্যাকওভারফ্লোতে আমি এ পর্যন্ত সবচেয়ে দীর্ঘ উত্তর লিখেছি। আশা করি এটা কাজে লাগবে. 😉


আমি এই দৃশ্যের সাথে স্ট্যাকওভারফ্লো.com/ প্রশ্নগুলি / 56363৪৯০৫২/২ আবেদন করছি তবে এটি কাজ করছে না। আপনি কি আমাকে বলবেন কীভাবে আমি এটি অর্জন করতে পারি
নাজমুল হাসান

এমনকি এটির সাথে (যা সত্যিই দুর্দান্ত একটি প্রকল্প) আমি আমার অ্যাপ্লিকেশনগুলিতে উল্লম্ব স্ক্রোলিং সংগ্রহের দৃশ্যে ঝলকানি অনুভব করি। আমার 20 টি কোষ রয়েছে এবং প্রথম স্ক্রোলটিতে প্রথম কক্ষটি ফাঁকা এবং সমস্ত ঘর একটি অবস্থান থেকে ডানে স্থানান্তরিত হয়। একটি এবং উপরে পুরো স্ক্রোল পরে, জিনিস সঠিকভাবে সারিবদ্ধ।
পার্থ তমনে

দুর্দান্ত প্রকল্প! এটিকে কার্থেজের জন্য সক্ষম করে দেখলে দুর্দান্ত হবে।
pjuzeliunas

30

আপনার প্রয়োজন অনুসারে সুইফট 4.1 এবং আইওএস 11 এর সাহায্যে, আপনার সমস্যা সমাধানের জন্য আপনি নিম্নলিখিত 2 টির মধ্যে একটি সম্পূর্ণ বাস্তবায়ন বেছে নিতে পারেন ।


# 1 বামদিকে অটোরেজিং UICollectionViewCellএস

নীচের বাস্তবায়নটি দেখায় যে কীভাবে UICollectionViewLayout's layoutAttributesForElements(in:), UICollectionViewFlowLayout' s estimatedItemSizeএবং UILabel's ব্যবহার করতে preferredMaxLayoutWidthহয় যাতে একটিতে অটোরেসাইজিং সেলগুলি বামে সাজানোর জন্য UICollectionView:

কালেকশনভিউকন্ট্রোলআর সুইফট

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)
    }

}

ফ্লোএলআউট.সুইফ্ট

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
    }

}

কালেকশনভিউসেল.সুইফ্ট

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:

কালেকশনভিউকন্ট্রোলআর সুইফট

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)
    }

}

ফ্লোএলআউট.সুইফ্ট

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
    }

}

কালেকশনভিউসেল.সুইফ্ট

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একটি স্বেচ্ছাসেবী সংখ্যা ব্যবহার করা হয় ?
amariduran

27

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
    }
}

এখানে চিত্র বর্ণনা লিখুন

এবং পরিশেষে...

উপরের @ অ্যালেক্সশুবিনকে ধন্যবাদ দিন যিনি প্রথমে এটি পরিষ্কার করেছেন!


আরে আমি একটু বিভ্রান্ত শুরুতে এবং স্ট্রিংয়ে প্রতিটি স্ট্রিংয়ের জন্য স্থান যুক্ত করা আমার আইটেম সেলে আমার শব্দটি ডাব্লু / ওয়ে যুক্ত করে shows কিভাবে এটি সম্পর্কে কোন ধারণা?
মোহাম্মদ লি

4
আপনার সংগ্রহে দেখার বিভাগে বিভাগে শিরোনাম থাকলে এটি তাদের হত্যা করে seems
টাইলারজেমস

22

প্রশ্নটি অনেকক্ষণ হয়ে গেছে তবে এর কোনও উত্তর নেই এবং এটি একটি ভাল প্রশ্ন। উত্তরটি হ'ল ইউআইকিউলেকশনভিউফ্লোলোআউট আউন সাবক্লাসে একটি পদ্ধতি ওভাররাইড করা:

@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

অ্যাপল দ্বারা প্রস্তাবিত হিসাবে, আপনি সুপার থেকে লেআউট বৈশিষ্ট্য পাবেন এবং সেগুলি দিয়ে পুনরাবৃত্তি করুন। যদি এটি সারিতে প্রথম হয় (বাম মার্জিনে থাকা এর উত্স দ্বারা নির্ধারিত হয়) তবে আপনি এটিকে একা রেখে শূন্যে x পুনরায় সেট করুন। তারপরে প্রথম কক্ষ এবং প্রতিটি কক্ষের জন্য, আপনি সেই ঘরের প্রস্থটি যোগ করুন এবং কিছু মার্জিন। এটি লুপের পরবর্তী আইটেমটিতে পৌঁছে যায়। এটি যদি প্রথম আইটেম না হয় তবে আপনি চলমান গণনা করা মার্জিনে এটি মূল.x নির্ধারণ করুন এবং অ্যারেতে নতুন উপাদান যুক্ত করুন।


আমি মনে করি এই ভাবে ক্রিস ওয়াগনার এর সমাধান (বেশী ভালো stackoverflow.com/a/15554667/482557 লিঙ্ক প্রশ্নোত্তর আপনার বাস্তবায়ন দিকে) শূন্য পুনরাবৃত্তিমূলক UICollectionViewLayout কল হয়েছে।
ইভান আর

4
সারিটিতে যদি একটি আইটেম থাকে তবে এগুলি কাজ করে না বলে মনে হয় কারণ ইউআইকোলিকেশনভিউফ্লোএলআউট এটি কেন্দ্র করে। সমস্যাটি সমাধান করার জন্য আপনি কেন্দ্রটি পরীক্ষা করতে পারেন। এর মতো কিছুattribute.center.x == self.collectionView?.bounds.midX
রায়ান পুলোস

আমি এটি প্রয়োগ করেছি, তবে কোনও কারণে এটি প্রথম বিভাগের জন্য বিরতি দেয়: প্রথম ঘরটি প্রথম সারির বাম দিকে প্রদর্শিত হয় এবং দ্বিতীয় ঘরটি (যা একই সারিতে ফিট করে না) পরবর্তী সারিতে যায় তবে বাম হয় না সারিবদ্ধ পরিবর্তে, এর প্রথম অবস্থান শুরু হয় যেখানে প্রথম ঘরটি শেষ হয়।
নিকোলাস মিয়ারি

@ নিকোলাসমিয়ারি লুপটি এটি একটি নতুন সারিটি স্থির করে এবং চেকটি leftMarginদিয়ে পুনরায় সেট করে if (attributes.frame.origin.x == self.sectionInset.left) {। এটি ধরে নিয়েছে যে ডিফল্ট লেআউটটি নতুন সারিটির ঘরটি এর সাথে ফ্ল্যাশ করতে সংযুক্ত করেছে sectionInset.left। যদি এটি না হয়, আপনার বর্ণনার আচরণের ফলাফল হবে result আমি লুপটির ভিতরে একটি ব্রেকপয়েন্টটি প্রবেশ করিয়ে তুলনা করার ঠিক আগে দ্বিতীয় সারির সেলটির জন্য উভয় পক্ষের পরীক্ষা করতাম ভাগ্য সুপ্রসন্ন হোক.
মাইক স্যান্ড 17

4
ধন্যবাদ ... আমি ইউআইসিকলিকশনভিউ লেফটএলিন্ডলয়আউট: github.com/mokagio/UICollectionViewLeftAlignLayout ব্যবহার করে শেষ করেছি । এটি আরও কয়েকটি পদ্ধতির ওভাররাইড করে।
নিকোলাস মিয়ারি

9

আমার একই সমস্যা ছিল, কোকোপড ইউআইসি কলিকেশনভিউ লেফটএলাইন্টএলইন্ট একবার চেষ্টা করুন। এটি কেবল আপনার প্রকল্পে অন্তর্ভুক্ত করুন এবং এটি এর মতো সূচনা করুন:

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

আপনার সেখানে বিন্যাসের
সূচনাতে

আমি github.com/eroth/ERJustifiedFlowLayout এবং UICol લેક્શન ভিউ লেফটএলিন্টলয়েট দুটি উত্তর পরীক্ষা করেছি। আনুমানিক আইটেম সাইজ (স্ব-আকার নির্ধারণ) ব্যবহার করার সময় কেবলমাত্র দ্বিতীয়টি সঠিক ফলাফল দেয়।
এখার্ডএন

6

সুইফটে আসল উত্তরটি এখানে। এটি এখনও বেশিরভাগ ক্ষেত্রে দুর্দান্ত কাজ করে।

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's 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
    }
}

এটি প্রথম বিভাগের জন্য কাজ করে তবে সারণী স্ক্রোলগুলি না হওয়া পর্যন্ত লেবেলটি দ্বিতীয় বিভাগটির আকার পরিবর্তন করে না। আমার সংগ্রহের দৃশ্যটি টেবিল ঘরে রয়েছে।
EI ক্যাপ্টেন v2.0

5

মাইকেল স্যান্ডের উত্তরের উপর ভিত্তি করে , আমি UICollectionViewFlowLayoutবাম, ডান বা পুরো (মূলত ডিফল্ট) অনুভূমিক ন্যায়সঙ্গতকরণের জন্য একটি উপক্ল্যাসেড লাইব্রেরি তৈরি করেছি - এটি আপনাকে প্রতিটি ঘরের মধ্যে পরম দূরত্ব নির্ধারণ করতে দেয়। আমি এটির অনুভূমিক কেন্দ্রের ন্যায়সঙ্গততা এবং উল্লম্ব ন্যায়সঙ্গত যুক্ত করার পরিকল্পনা করছি।

https://github.com/eroth/ERJustifiedFlowLayout


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
    }
}

সিজিফ্লোট মানগুলির তুলনা করার জায়গায় আইএনটি ব্যবহার করুন ।


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

সুইফট ৫ এর সাথে কাজ করে এমন সেরা কোডটি সন্ধানের জন্য আমার এখানে যাত্রা। আমি এই থ্রেড থেকে উত্তর এবং কয়েকটা সতর্কতা এবং সমস্যার মুখোমুখি হওয়া সমস্যাগুলি সমাধান করার জন্য কিছু অন্যান্য থ্রেডের সাথে যুক্ত হয়েছি। আমার সংগ্রহের দৃশ্যের মাধ্যমে স্ক্রোল করার সময় আমার একটি সতর্কতা এবং কিছু অস্বাভাবিক আচরণ ছিল। কনসোল নিম্নলিখিত মুদ্রণ:

এটি সম্ভবত ঘটছে কারণ প্রবাহের বিন্যাস "xyz" ইউআইকোলিকেশনভিউ ফ্লোলায়আউটকে অনুলিপি না করে ফিরিয়ে দেওয়া বৈশিষ্ট্যগুলি সংশোধন করছে।

আমি আর একটি সমস্যার মুখোমুখি হলাম যে স্ক্রিনের ডানদিকে কয়েকটি দীর্ঘ কক্ষগুলি ক্রপ হচ্ছে। এছাড়াও, আমি বিভাগের ইনসেটগুলি এবং ডেলিগেট ফাংশনগুলিতে ন্যূনতমতম ইন্টারমেটেমস্পেসিং সেট করছিলাম যার ফলস্বরূপ মানগুলি কাস্টম শ্রেণিতে প্রতিফলিত হয়নি। এর সমাধানটি আমার সংগ্রহ দর্শনে প্রয়োগ করার আগে লেআউটটির কোনও উদাহরণে সেই বৈশিষ্ট্যগুলি সেট করে was

আমি এখানে আমার সংগ্রহ দেখার জন্য লেআউটটি কীভাবে ব্যবহার করেছি:

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
    }
}

আপনি আমার দিনটি রক্ষা করেছেন
ডেভিড 'এমআরএম' আনসারমোট

0

ইউআইকোলিকেশনভিউয়ের সমস্যাটি হ'ল এটি উপলব্ধ অঞ্চলে স্বয়ংক্রিয়ভাবে ঘরগুলি ফিট করার চেষ্টা করে। আমি প্রথমে সারি এবং কলামগুলির সংখ্যা নির্ধারণ করে এবং তারপরে সেই সারি এবং কলামের জন্য ঘর আকার নির্ধারণ করে এটি করেছি

1) আমার ইউআইকোলিকেশনভিউয়ের বিভাগগুলি (সারিগুলি) সংজ্ঞায়িত করতে:

(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView

২) একটি বিভাগে আইটেমের সংখ্যা নির্ধারণ করা। আপনি প্রতিটি বিভাগের জন্য বিভিন্ন সংখ্যক আইটেম সংজ্ঞায়িত করতে পারেন। আপনি 'বিভাগ' পরামিতি ব্যবহার করে বিভাগ নম্বর পেতে পারেন।

(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

দ্রষ্টব্য: ইউআইসিকল্যাশনভিউতে

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
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.