UICollectionView เซลล์แบบเต็มความกว้างอนุญาตให้กำหนดค่าความสูงแบบไดนามิกอัตโนมัติหรือไม่


120

ในแนวตั้งUICollectionView,

มันเป็นไปได้ที่จะมีเซลล์เต็มความกว้างแต่อนุญาตให้สูงแบบไดนามิกจะถูกควบคุมโดยautolayout ?

นี่อาจทำให้ฉันรู้สึกว่าเป็น "คำถามที่สำคัญที่สุดใน iOS ที่ไม่มีคำตอบที่ดีจริงๆ"


สำคัญ:

โปรดทราบว่าใน 99% ของกรณีเพื่อให้ได้เซลล์ที่มีความกว้างเต็ม + การกำหนดค่าความสูงแบบไดนามิกอัตโนมัติเพียงแค่ใช้มุมมองตาราง มันง่ายมาก


ตัวอย่างของตำแหน่งที่คุณต้องการมุมมองคอลเลคชันคืออะไร?

มุมมองคอลเลคชันมีประสิทธิภาพมากกว่าการดูตารางอย่างไม่น่าเชื่อ

ตัวอย่างที่ตรงไปตรงมาอย่างหนึ่งที่คุณต้องใช้มุมมองคอลเลคชันเพื่อให้ได้เซลล์แบบเต็มความกว้าง + ความสูงแบบไดนามิกอัตโนมัติ

หากคุณเคลื่อนไหวระหว่างสองเค้าโครงในมุมมองคอลเลกชัน ตัวอย่างเช่นระหว่างเค้าโครงคอลัมน์ 1 ถึง 2 เมื่ออุปกรณ์หมุน

นั่นเป็นสำนวนทั่วไปและปกติใน iOS น่าเสียดายที่สามารถทำได้โดยการแก้ปัญหาที่เกิดขึ้นใน QA นี้เท่านั้น : - /


ใช่เป็นไปได้ด้วยคลาส UICollectionViewDelegateFlowLayout
Sunil Prajapati

นี่หมายความว่าคุณสามารถใช้ tableView ได้จริงหรือ? ฟังก์ชันเพิ่มเติมใดที่จำเป็นสำหรับคุณในการทำสิ่งนี้มากเกินไป
Catalina T.

1
สวัสดี @CatalinaT. มุมมองคอลเลกชันมีคุณสมบัติเพิ่มเติมมากมายหลายรายการในมุมมองตาราง ตัวอย่างง่ายๆคือการเพิ่มฟิสิกส์ (ถ้าคุณไม่รู้ว่าฉันหมายถึงอะไรคุณสร้างรายการ "ตีกลับ" ใน iOS ได้อย่างไร)
Fattie

คุณยังสามารถใช้ฟิสิกส์ (เช่นSpringDampingและinitialSpringVelocity) ในตารางเซลล์ได้อีกด้วย ..... ดู Bouncy List นี้โดยใช้ tableView``,, pastebin.com/pFRQhkrX คุณสามารถเคลื่อนไหวTableViewCellในตารางในwillDisplayCell:(UITableViewCell *)cellวิธีการเดลเกต @Fattie ที่คุณยอมรับได้ คำตอบที่แก้ไขปัญหาของคุณเพื่อช่วยเหลือผู้อื่นที่กำลังมองหาปัญหาเดียวกัน
Dhiru

โอเคคุณลองรายการ Bouncy โดยใช้มุมมองรายการหรือไม่? @Fattie
Dhiru

คำตอบ:


127

1. โซลูชันสำหรับ iOS 13+

ด้วย Swift 5.1 และ iOS 13 คุณสามารถใช้ออบเจ็กต์เค้าโครงองค์ประกอบเพื่อแก้ปัญหาของคุณได้

โค้ดตัวอย่างที่สมบูรณ์ต่อไปนี้แสดงวิธีการแสดงหลายบรรทัดUILabelภายในความกว้างเต็มUICollectionViewCell:

CollectionViewController.swift

import UIKit

class CollectionViewController: UICollectionViewController {

    let items = [
        [
            "Lorem ipsum dolor sit amet.",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
        ],
        [
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt.",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
        ],
        [
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt.",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
            "Lorem ipsum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.",
        ]
    ]

    override func viewDidLoad() {
        super.viewDidLoad()

        let size = NSCollectionLayoutSize(
            widthDimension: NSCollectionLayoutDimension.fractionalWidth(1),
            heightDimension: NSCollectionLayoutDimension.estimated(44)
        )
        let item = NSCollectionLayoutItem(layoutSize: size)
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: size, subitem: item, count: 1)

        let section = NSCollectionLayoutSection(group: group)
        section.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)
        section.interGroupSpacing = 10

        let headerFooterSize = NSCollectionLayoutSize(
            widthDimension: .fractionalWidth(1.0),
            heightDimension: .absolute(40)
        )
        let sectionHeader = NSCollectionLayoutBoundarySupplementaryItem(
            layoutSize: headerFooterSize,
            elementKind: "SectionHeaderElementKind",
            alignment: .top
        )
        section.boundarySupplementaryItems = [sectionHeader]

        let layout = UICollectionViewCompositionalLayout(section: section)
        collectionView.collectionViewLayout = layout
        collectionView.register(CustomCell.self, forCellWithReuseIdentifier: "CustomCell")
        collectionView.register(HeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HeaderView")
    }

    override func numberOfSections(in collectionView: UICollectionView) -> Int {
        return items.count
    }

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

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

    override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HeaderView", for: indexPath) as! HeaderView
        headerView.label.text = "Header"
        return headerView
    }

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        coordinator.animate(alongsideTransition: { context in
            self.collectionView.collectionViewLayout.invalidateLayout()
        }, completion: nil)
    }

}

HeaderView.swift

import UIKit

class HeaderView: UICollectionReusableView {

    let label = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .magenta

        addSubview(label)
        label.translatesAutoresizingMaskIntoConstraints = false
        label.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
        label.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
    }

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

}

CustomCell.swift

import UIKit

class CustomCell: UICollectionViewCell {

    let label = UILabel()

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

        label.numberOfLines = 0
        backgroundColor = .orange
        contentView.addSubview(label)

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

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

}

การแสดงผลที่คาดหวัง:

ใส่คำอธิบายภาพที่นี่


2. โซลูชันสำหรับ iOS 11+

ด้วย Swift 5.1 และ iOS 11 คุณสามารถซับคลาสUICollectionViewFlowLayoutและตั้งค่าestimatedItemSizeคุณสมบัติเป็นUICollectionViewFlowLayout.automaticSize(สิ่งนี้จะบอกระบบว่าคุณต้องการจัดการกับการปรับUICollectionViewCellขนาดอัตโนมัติ) จากนั้นคุณจะต้องลบล้างlayoutAttributesForElements(in:)และlayoutAttributesForItem(at:)กำหนดความกว้างของเซลล์ สุดท้ายคุณจะต้องลบล้างpreferredLayoutAttributesFitting(_:)เมธอดของเซลล์และคำนวณความสูงของเซลล์

โค้ดที่สมบูรณ์ต่อไปนี้แสดงวิธีการแสดงหลายบรรทัดUILabelภายในแบบเต็มความกว้างUIcollectionViewCell(จำกัด โดยUICollectionViewพื้นที่ปลอดภัยและสิ่งUICollectionViewFlowLayoutที่ใส่เข้าไป):

CollectionViewController.swift

import UIKit

class CollectionViewController: UICollectionViewController {

    let items = [
        [
            "Lorem ipsum dolor sit amet.",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
        ],
        [
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt.",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
        ],
        [
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt.",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
            "Lorem ipsum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.",
        ]
    ]
    let customFlowLayout = CustomFlowLayout()

    override func viewDidLoad() {
        super.viewDidLoad()

        customFlowLayout.sectionInsetReference = .fromContentInset // .fromContentInset is default
        customFlowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
        customFlowLayout.minimumInteritemSpacing = 10
        customFlowLayout.minimumLineSpacing = 10
        customFlowLayout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
        customFlowLayout.headerReferenceSize = CGSize(width: 0, height: 40)

        collectionView.collectionViewLayout = customFlowLayout
        collectionView.contentInsetAdjustmentBehavior = .always
        collectionView.register(CustomCell.self, forCellWithReuseIdentifier: "CustomCell")
        collectionView.register(HeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HeaderView")
    }

    override func numberOfSections(in collectionView: UICollectionView) -> Int {
        return items.count
    }

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

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

    override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HeaderView", for: indexPath) as! HeaderView
        headerView.label.text = "Header"
        return headerView
    }

}

CustomFlowLayout.swift

import UIKit

final class CustomFlowLayout: UICollectionViewFlowLayout {

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let layoutAttributesObjects = super.layoutAttributesForElements(in: rect)?.map{ $0.copy() } as? [UICollectionViewLayoutAttributes]
        layoutAttributesObjects?.forEach({ layoutAttributes in
            if layoutAttributes.representedElementCategory == .cell {
                if let newFrame = layoutAttributesForItem(at: layoutAttributes.indexPath)?.frame {
                    layoutAttributes.frame = newFrame
                }
            }
        })
        return layoutAttributesObjects
    }

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        guard let collectionView = collectionView else {
            fatalError()
        }
        guard let layoutAttributes = super.layoutAttributesForItem(at: indexPath)?.copy() as? UICollectionViewLayoutAttributes else {
            return nil
        }

        layoutAttributes.frame.origin.x = sectionInset.left
        layoutAttributes.frame.size.width = collectionView.safeAreaLayoutGuide.layoutFrame.width - sectionInset.left - sectionInset.right
        return layoutAttributes
    }

}

HeaderView.swift

import UIKit

class HeaderView: UICollectionReusableView {

    let label = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .magenta

        addSubview(label)
        label.translatesAutoresizingMaskIntoConstraints = false
        label.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
        label.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
    }

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

}

CustomCell.swift

import UIKit

class CustomCell: UICollectionViewCell {

    let label = UILabel()

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

        label.numberOfLines = 0
        backgroundColor = .orange
        contentView.addSubview(label)

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

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

    override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
        let layoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes)
        layoutIfNeeded()
        layoutAttributes.frame.size = systemLayoutSizeFitting(UIView.layoutFittingCompressedSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
        return layoutAttributes
    }

}

นี่คือการใช้งานทางเลือกบางอย่างสำหรับpreferredLayoutAttributesFitting(_:):

override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
    let targetSize = CGSize(width: layoutAttributes.frame.width, height: 0)
    layoutAttributes.frame.size = contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
    return layoutAttributes
}
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
    label.preferredMaxLayoutWidth = layoutAttributes.frame.width
    layoutAttributes.frame.size.height = contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
    return layoutAttributes
}

การแสดงผลที่คาดหวัง:

ใส่คำอธิบายภาพที่นี่


สิ่งนี้ใช้ได้ดีสำหรับฉันจนกว่าฉันจะเพิ่มส่วนหัว ส่วนหัวของส่วนถูกใส่ผิดตำแหน่งและครอบคลุมเซลล์อื่น ๆ ใน iOS 11 แต่ใช้งานได้ดีใน iOS 12 คุณประสบปัญหาในการเพิ่มส่วนหัวหรือไม่?
กุล

ขอบคุณมาก. คุณบันทึกสัปดาห์ของฉัน 🙇‍♂️
Gaetan

1
CollectionView จะเลื่อนขึ้นไปด้านบนเมื่อใดก็ตามที่ขนาดเปลี่ยนไป
Sajith

1
ข่าวดี @ImanouPetit! ฉันหวังว่าค่าหัวจะใหญ่กว่านี้! ข้อมูลที่ยอดเยี่ยมเกี่ยวกับวัตถุเค้าโครงองค์ประกอบขอบคุณ
Fattie

1
สวัสดีฉันกำลังพยายามอยู่ แม้ว่าฉันจะตั้งค่าเค้าโครงใน viewdidload ตามที่คุณทำข้างต้น แต่ฉันได้รับข้อขัดข้องที่ระบุว่าต้องเริ่มต้น collectionview ด้วยพารามิเตอร์โครงร่างที่ไม่ใช่ศูนย์ มีบางอย่างที่ฉันขาดหายไป? นี่คือ Xcode 11 สำหรับ iOS 13
geistmate

29

ปัญหา

คุณกำลังมองหาความสูงอัตโนมัติและต้องการมีความกว้างเต็มจึงไม่สามารถใช้ทั้งสองUICollectionViewFlowLayoutAutomaticSizeอย่างได้

คุณต้องการทำโดยใช้UICollectionViewด้านล่างนี้เป็นทางออกสำหรับคุณ

สารละลาย

ขั้นตอนที่ 1 : คำนวณความสูงที่คาดหวังของเซลล์

1.ถ้าคุณมีเพียงUILabel ในCollectionViewCellกว่ากำหนดnumberOfLines=0และคำนวณความสูงที่คาดว่าจะUIlableผ่านทั้งสามพารามิเตอร์

func heightForLable(text:String, font:UIFont, width:CGFloat) -> CGFloat {
    // pass string, font, LableWidth  
    let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
     label.numberOfLines = 0
     label.lineBreakMode = NSLineBreakMode.byWordWrapping
     label.font = font
     label.text = text
     label.sizeToFit()

     return label.frame.height
}

2.ถ้าCollectionViewCellมีของคุณเท่านั้นUIImageViewและถ้ามันควรจะเป็นแบบไดนามิกในความสูงมากกว่าที่คุณต้องการเพื่อให้ได้ความสูงUIImage (คุณUIImageViewต้องมีAspectRatioข้อ จำกัด )

// this will give you the height of your Image
let heightInPoints = image.size.height
let heightInPixels = heightInPoints * image.scale

3. หากมีทั้งความสูงมากกว่าที่คำนวณไว้ให้บวกเข้าด้วยกัน

STEP-II : คืนขนาดของCollectionViewCell

1.เพิ่มUICollectionViewDelegateFlowLayoutผู้รับมอบสิทธิ์ใน viewController ของคุณ

2.ใช้วิธีการมอบหมาย

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

    // This is just for example, for the scenario Step-I -> 1 
    let yourWidthOfLable=self.view.size.width
    let font = UIFont(name: "Helvetica", size: 20.0)

    var expectedHeight = heightForLable(array[indePath.row], font: font, width:yourWidthOfLable)


    return CGSize(width: view.frame.width, height: expectedHeight)
}

ฉันหวังว่านี่จะช่วยคุณได้


1
เป็นไปได้หรือไม่ที่จะมี UICollectionView แบบเลื่อนในแนวนอนที่มีความสูงของเซลล์เพิ่มขึ้นในแนวตั้งด้วยรูปแบบอัตโนมัติ
nr5

ฉันต้องการทำให้สำเร็จเท่ากัน แต่มีความกว้างครึ่งหนึ่งและความสูงแบบไดนามิก
Mihir Mehta

return CGSize(width: view.frame.width/2, height: expectedHeight)เก็บ Padding ไว้ในบัญชีแทนที่จะคืนความกว้างมิฉะนั้นเซลล์สองเซลล์จะไม่พอดีในแถวเดียว
Dhiru

@ nr5 คุณได้รับการแก้ปัญหาหรือไม่? ความต้องการของฉันเหมือนกับของคุณ ขอบคุณ.
Maulik Bhuptani

@MaulikBhuptani ฉันไม่สามารถทำได้อย่างสมบูรณ์กับเค้าโครงอัตโนมัติ ต้องสร้างคลาส Layout แบบกำหนดเองและแทนที่เมธอดคลาสบางอย่าง
5

18

มีสองวิธีที่คุณสามารถจัดการกับปัญหานี้ได้

วิธีหนึ่งคือคุณสามารถให้เค้าโครงโฟลว์มุมมองคอลเลกชันขนาดโดยประมาณและคำนวณขนาดเซลล์ได้

หมายเหตุ: ตามที่กล่าวไว้ในความคิดเห็นด้านล่างใน iOS 10 คุณไม่จำเป็นต้องระบุและขนาดโดยประมาณเพื่อเรียกใช้การโทรไปยังเซลล์ func preferredLayoutAttributesFitting(_ layoutAttributes:)อีกต่อไป ก่อนหน้านี้ (iOS 9) ต้องการให้คุณระบุขนาดโดยประมาณหากคุณต้องการสอบถามเซลล์ prefferedLayoutAttributes

(สมมติว่าคุณใช้สตอรีบอร์ดและมุมมองคอลเลคชันเชื่อมต่อผ่าน IB)

override func viewDidLoad() {
    super.viewDidLoad()
    let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
    layout?.estimatedItemSize = CGSize(width: 375, height: 200) // your average cell size
}

สำหรับเซลล์ธรรมดานั้นมักจะเพียงพอ หากขนาดยังคงไม่ถูกต้องในเซลล์มุมมองคอลเลกชันคุณสามารถแทนที่func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributesได้ซึ่งจะทำให้คุณสามารถควบคุมขนาดของเซลล์ได้อย่างละเอียดมากขึ้น หมายเหตุ: คุณยังคงต้องกำหนดขนาดโดยประมาณให้กับเค้าโครงโฟลว์

จากนั้นแทนที่func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributesเพื่อส่งคืนขนาดที่ถูกต้อง

override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
    let autoLayoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes)
    let targetSize = CGSize(width: layoutAttributes.frame.width, height: 0)
    let autoLayoutSize = contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: UILayoutPriorityRequired, verticalFittingPriority: UILayoutPriorityDefaultLow)
    let autoLayoutFrame = CGRect(origin: autoLayoutAttributes.frame.origin, size: autoLayoutSize)
    autoLayoutAttributes.frame = autoLayoutFrame
    return autoLayoutAttributes
}

หรือคุณสามารถใช้เซลล์ปรับขนาดเพื่อคำนวณขนาดของเซลล์ในไฟล์ UICollectionViewDelegateFlowLayout.

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let width = collectionView.frame.width
    let size = CGSize(width: width, height: 0)
    // assuming your collection view cell is a nib
    // you may also instantiate a instance of our cell from a storyboard
    let sizingCell = UINib(nibName: "yourNibName", bundle: nil).instantiate(withOwner: nil, options: nil).first as! YourCollectionViewCell
    sizingCell.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    sizingCell.frame.size = size
    sizingCell.configure(with: object[indexPath.row]) // what ever method configures your cell
    return sizingCell.contentView.systemLayoutSizeFitting(size, withHorizontalFittingPriority: UILayoutPriorityRequired, verticalFittingPriority: UILayoutPriorityDefaultLow)
}

แม้ว่าสิ่งเหล่านี้จะไม่ใช่ตัวอย่างที่พร้อมสำหรับการผลิตที่สมบูรณ์แบบ แต่ก็ควรช่วยให้คุณเริ่มต้นไปในทิศทางที่ถูกต้อง ฉันไม่สามารถพูดได้ว่านี่เป็นแนวทางปฏิบัติที่ดีที่สุด แต่วิธีนี้ใช้ได้ผลกับฉันแม้จะมีเซลล์ที่ค่อนข้างซับซ้อนซึ่งมีป้ายกำกับหลายป้ายซึ่งอาจหรือไม่รวมกันเป็นหลายบรรทัดก็ได้


@Fattie ไม่ชัดเจนว่า 'esitmatedItemSize' ไม่เกี่ยวข้องกับเซลล์มุมมองคอลเลกชันที่มีขนาดแบบไดนามิกดังนั้นฉันจึงอยากฟังความคิดเห็นของคุณ (ไม่ใช่การถากถาง)
Eric Murphey

นอกจากนี้หากคำตอบนี้ไม่มีบางสิ่งที่เฉพาะเจาะจงเพื่อเป็นประโยชน์และ / หรือสิ่งที่คุณคิดว่าเป็นบัญญัติโปรดแจ้งให้เราทราบ ฉันจะไม่เถียงเรื่องค่าหัวฉันแค่อยากจะเป็นประโยชน์กับคนอื่น ๆ ที่ดูคำถามนี้
Eric Murphey

1
(รวมถึงหรือไม่รวมค่าประมาณ ItemSize ทำให้ไม่มีความแตกต่างใน iOS ปัจจุบันและไม่มีความช่วยเหลือ แต่อย่างใดในปัญหา "ความกว้างเต็ม + ความสูงแบบไดนามิก") โค้ดในตอนท้ายแทบจะไม่ได้ใช้หัวปากกาในปัจจุบันและมี ความเกี่ยวข้องเล็กน้อยกับความสูงแบบไดนามิก (จากตัวอย่างเช่นมุมมองข้อความความสูงแบบไดนามิกบางส่วน) ขอบคุณ
Fattie

ฉันมาถึงโซลูชันนี้เช่นกัน แต่ในกรณีของฉัน iOS 11, Xcode 9.2 ดูเหมือนว่าเนื้อหาของเซลล์จะถูกตัดการเชื่อมต่อจากเซลล์ - ฉันไม่สามารถรับภาพเพื่อขยายให้เต็มความสูงหรือความกว้างของขนาดคงที่ได้ ฉันสังเกตเพิ่มเติมว่า CV เป็นข้อ จำกัด ในการตั้งค่าในpreferredLayoutAttributesFitting. จากนั้นฉันได้เพิ่มข้อ จำกัด ของตัวเองในฟังก์ชันดังกล่าวโดยผูกกับมิติข้อมูลคงที่จากค่าประมาณรายการขนาด FWIW ดูคำตอบของฉันด้านล่าง
Chris Conover

16

ฉันพบวิธีแก้ปัญหาที่ค่อนข้างง่ายสำหรับปัญหานั้น: ภายใน CollectionViewCell ของฉันฉันได้รับ UIView () ซึ่งเป็นเพียงพื้นหลังเท่านั้น เพื่อให้ได้ความกว้างเต็มฉันเพียงแค่ตั้งจุดยึดต่อไปนี้

bgView.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.size.width - 30).isActive = true // 30 is my added up left and right Inset
bgView.topAnchor.constraint(equalTo: topAnchor).isActive = true
bgView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
bgView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
bgView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true

"เวทมนตร์" เกิดขึ้นในบรรทัดแรก ฉันตั้งค่า widthAnchor แบบไดนามิกเป็นความกว้างของหน้าจอ สิ่งสำคัญคือการลบสิ่งที่ใส่เข้าไปใน CollectionView ของคุณ มิฉะนั้นเซลล์จะไม่ปรากฏขึ้น หากคุณไม่ต้องการให้มีมุมมองพื้นหลังแบบนี้ให้มองไม่เห็น

FlowLayout ใช้การตั้งค่าต่อไปนี้

layout.itemSize = UICollectionViewFlowLayoutAutomaticSize
layout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize

ผลลัพธ์คือเซลล์ขนาดความกว้างเต็มที่มีความสูงแบบไดนามิก

ใส่คำอธิบายภาพที่นี่


1
วัวศักดิ์สิทธิ์ - น่าทึ่งมาก! ชัด ๆ ! แจ่ม!
Fattie

1
แค่ TBC @ inf1783 คุณกำลังทำสิ่งนี้ใน UICollectionView? (ไม่ใช่มุมมองตาราง) - ถูกต้องหรือไม่?
Fattie

1
@Fattie ใช่มันเป็น UICollectionView;)
inf1783

เยี่ยมมาก @ inf1783 อดใจรอไม่ไหวแล้ว อย่างไรก็ตามอีกวิธีที่ดีในการทำเช่นนั้นคือการ subclass UIView และเพิ่มความกว้างภายใน (ฉันเดาว่ามันจะมีผลเหมือนกันและมันอาจจะทำให้มันใช้งานได้ในเวลากระดานเรื่องราวด้วย)
Fattie

1
ทุกครั้งที่ฉันลองสิ่งนี้ฉันจะจบลงด้วยการวนซ้ำไม่รู้จบด้วยพฤติกรรมของ UICollectionViewFlowLayout ไม่ได้กำหนดข้อผิดพลาด: /
Skodik.o

7

ทำงาน !!! ทดสอบบน IOS: 12.1 Swift 4.1

ฉันมีวิธีง่ายๆที่ใช้งานได้โดยไม่มีการทำลายข้อ จำกัด

ใส่คำอธิบายภาพที่นี่

ViewControllerClass ของฉัน

class ViewController: UIViewController {

    @IBOutlet weak var collectionView: UICollectionView!

    let cellId = "CustomCell"

    var source = ["nomu", "when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. ", "t is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by", "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia,","nomu", "when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. ", "t is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by", "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia,","nomu", "when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. ", "t is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by", "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia,"]

    override func viewDidLoad() {
        super.viewDidLoad()

        self.collectionView.delegate = self
        self.collectionView.dataSource = self
        self.collectionView.register(UINib.init(nibName: cellId, bundle: nil), forCellWithReuseIdentifier: cellId)

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

    }

}


extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource {

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

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as? CustomCell else { return UICollectionViewCell() }
        cell.setData(data: source[indexPath.item])
        return cell
    }


}

คลาส CustomCell:

class CustomCell: UICollectionViewCell {

    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var widthConstraint: NSLayoutConstraint!

    override func awakeFromNib() {
        super.awakeFromNib()
        self.widthConstraint.constant = UIScreen.main.bounds.width
    }

    func setData(data: String) {
        self.label.text = data
    }

    override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
        return contentView.systemLayoutSizeFitting(CGSize(width: self.bounds.size.width, height: 1))
    }

}

ส่วนผสมหลักเป็นsystemLayoutSizeFittingฟังก์ชั่นใน Customcell และเราต้องกำหนดความกว้างของมุมมองภายในเซลล์ด้วยข้อ จำกัด


6

คุณต้องเพิ่มข้อ จำกัด ด้านความกว้างให้กับ CollectionViewCell

class SelfSizingCell: UICollectionViewCell {

  override func awakeFromNib() {
      super.awakeFromNib()
      contentView.translatesAutoresizingMaskIntoConstraints = false
      contentView.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width).isActive = true
  }
}

ในที่สุดก็มีคนทำให้มันสมบูรณ์แบบในสองบรรทัด
Omar N Shamali

สิ่งนี้จะ จำกัด เซลล์ให้มีความกว้างคงที่แทบจะไม่ปรับขนาดเอง หากคุณต้องหมุนอุปกรณ์หรือปรับขนาดหน้าจอบน iPad อุปกรณ์จะยังคงอยู่
Thomas Verbeek

4
  1. ชุดestimatedItemSizeเค้าโครงโฟลว์ของคุณ:

    collectionViewLayout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize
  2. กำหนดข้อ จำกัด ด้านความกว้างในเซลล์และกำหนดให้เท่ากับความกว้างของ superview:

    class CollectionViewCell: UICollectionViewCell {
        private var widthConstraint: NSLayoutConstraint?
    
        ...
    
        override init(frame: CGRect) {
            ...
            // Create width constraint to set it later.
            widthConstraint = contentView.widthAnchor.constraint(equalToConstant: 0)
        }
    
        override func updateConstraints() {
            // Set width constraint to superview's width.
            widthConstraint?.constant = superview?.bounds.width ?? 0
            widthConstraint?.isActive = true
            super.updateConstraints()
        }
    
        ...
    }

ตัวอย่างเต็ม

ทดสอบบน iOS 11


3

โดยส่วนตัวแล้วฉันพบวิธีที่ดีที่สุดในการมี UICollectionView โดยที่ AutoLayout กำหนดขนาดในขณะที่แต่ละเซลล์สามารถมีขนาดที่แตกต่างกันคือการใช้ฟังก์ชัน UICollectionViewDelegateFlowLayout sizeForItemAtIndexPath ในขณะที่ใช้ Cell จริงเพื่อวัดขนาด

ฉันได้พูดถึงเรื่องนี้ในบล็อกโพสต์ของฉัน

หวังว่าสิ่งนี้จะช่วยให้คุณบรรลุสิ่งที่คุณต้องการ ฉันไม่แน่ใจ 100% แต่ฉันเชื่อว่าแตกต่างจาก UITableView ตรงที่คุณสามารถมีความสูงอัตโนมัติของเซลล์ได้โดยใช้ความไม่ต่อเนื่องของโครงร่างอัตโนมัติกับ

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 44

UICollectionView ไม่มีวิธีให้ AutoLayout กำหนดขนาดเนื่องจาก UICollectionViewCell ไม่จำเป็นต้องเติมเต็มความกว้างทั้งหมดของหน้าจอ

แต่นี่เป็นคำถามสำหรับคุณ : หากคุณต้องการเซลล์ความกว้างเต็มหน้าจอทำไมคุณถึงต้องใช้ UICollectionView กับ UITableView แบบเก่าที่ดีซึ่งมาพร้อมกับเซลล์ปรับขนาดอัตโนมัติ


ถือไว้ Aprit ด้านล่างกำลังบอกว่า UICollectionViewFlowLayoutAutomaticSize พร้อมใช้งานแล้วในรูปแบบโฟลว์ใน iOS10 ...
Fattie

ฉันยังเพิ่งเห็นสิ่งนี้ เห็นได้ชัดว่าเป็นสิ่งที่ตอนนี้ใน iOS 10 ฉันเพิ่งดู WWDC พูดคุยเกี่ยวกับสิ่งนี้: developer.apple.com/videos/play/wwdc2016/219อย่างไรก็ตามสิ่งนี้จะปรับขนาดเซลล์โดยอัตโนมัติให้พอดีกับเนื้อหา ฉันไม่แน่ใจว่าคุณจะบอกให้เซลล์ (ด้วย AutoLayout) เติมเต็มความกว้างของหน้าจอได้อย่างไรเนื่องจากคุณไม่สามารถตั้งค่าข้อ จำกัด ระหว่าง UICollectionViewCell และพาเรนต์ได้ (อย่างน้อยก็ไม่ใช่ใน StoryBoards)
xxtesaxx

ขวา. ดูเหมือนว่าเราจะไม่เข้าใกล้วิธีแก้ปัญหาที่แท้จริงของปัญหาที่ชัดเจนอย่างไม่น่าเชื่อนี้ : /
Fattie

จากการพูดคุยคุณยังคงสามารถเขียนทับ sizeThatFits () หรือ recommendedLayoutAttributesFitting () และคำนวณขนาดด้วยตัวเอง แต่นั่นไม่ใช่สิ่งที่ OP ขอให้ฉันคิด อย่างไรก็ตามฉันยังคงสนใจในกรณีการใช้งานเมื่อเขา / เธอต้องการ UICollectionViewCell แบบเต็มความกว้างและเหตุใดจึงเป็นเรื่องใหญ่ที่จะไม่ใช้ UITableView ในกรณีนี้ (แน่นอนว่าอาจมีบางกรณี แต่ฉันเดาว่า คุณต้องจัดการกับการคำนวณด้วยตัวเอง)
xxtesaxx

เมื่อคิดดูแล้วมันเหลือเชื่อมากที่คุณไม่สามารถตั้งค่า "คอลัมน์ == 1" ได้ง่ายๆ (และอาจเป็นคอลัมน์ == 2 เมื่ออุปกรณ์อยู่ด้านข้าง) ด้วยมุมมองคอลเลคชัน
Fattie

3

ตามความคิดเห็นของฉันเกี่ยวกับคำตอบของ Eric วิธีการแก้ปัญหาของฉันคล้ายกับของเขามาก แต่ฉันต้องเพิ่มข้อ จำกัด ใน recommendedSizeFor ... เพื่อ จำกัด มิติคงที่

    override func systemLayoutSizeFitting(
        _ targetSize: CGSize, withHorizontalFittingPriority
        horizontalFittingPriority: UILayoutPriority,
        verticalFittingPriority: UILayoutPriority) -> CGSize {

        width.constant = targetSize.width

        let size = contentView.systemLayoutSizeFitting(
            CGSize(width: targetSize.width, height: 1),
            withHorizontalFittingPriority: .required,
            verticalFittingPriority: verticalFittingPriority)

        print("\(#function) \(#line) \(targetSize) -> \(size)")
        return size
    }

คำถามนี้มีจำนวนที่ซ้ำกันฉันตอบโดยละเอียดที่นี่และให้ตัวอย่างแอปที่ใช้งานได้ที่นี่


2

ไม่แน่ใจว่าสิ่งนี้มีคุณสมบัติเป็น "คำตอบที่ดีจริงๆ" หรือไม่ แต่เป็นสิ่งที่ฉันใช้เพื่อทำสิ่งนี้ให้สำเร็จ เค้าโครงโฟลว์ของฉันเป็นแนวนอนและฉันกำลังพยายามปรับความกว้างด้วยการจัดวางอัตโนมัติดังนั้นจึงคล้ายกับสถานการณ์ของคุณ

extension PhotoAlbumVC: UICollectionViewDelegateFlowLayout {
  func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    // My height is static, but it could use the screen size if you wanted
    return CGSize(width: collectionView.frame.width - sectionInsets.left - sectionInsets.right, height: 60) 
  }
}

จากนั้นในตัวควบคุมมุมมองที่มีการแก้ไขข้อ จำกัด การจัดวางอัตโนมัติฉันจะปิดการแจ้งเตือน NSNotification

NotificationCenter.default.post(name: NSNotification.Name("constraintMoved"), object: self, userInfo: nil)

ในคลาสย่อย UICollectionView ของฉันฉันฟังการแจ้งเตือนนั้น:

// viewDidLoad
NotificationCenter.default.addObserver(self, selector: #selector(handleConstraintNotification(notification:)), name: NSNotification.Name("constraintMoved"), object: nil)

และทำให้เค้าโครงไม่ถูกต้อง:

func handleConstraintNotification(notification: Notification) {
    self.collectionView?.collectionViewLayout.invalidateLayout()
}

ซึ่งทำให้sizeForItemAtถูกเรียกอีกครั้งโดยใช้ขนาดใหม่ของมุมมองคอลเลกชัน ในกรณีของคุณควรอัปเดตได้ตามข้อ จำกัด ใหม่ที่มีอยู่ในเค้าโครง


แค่ TBC Mark หมายความว่าคุณกำลังเปลี่ยนขนาดของเซลล์จริงหรือ? (เช่นเซลล์จะปรากฏขึ้นและเป็นขนาด X จากนั้นมีบางอย่างเกิดขึ้นในแอปของคุณและกลายเป็นขนาด Y .. ?) thx
Fattie

ใช่. เมื่อผู้ใช้ลากองค์ประกอบบนหน้าจอเหตุการณ์จะเริ่มทำงานซึ่งจะอัปเดตขนาดของเซลล์
Mark Suman

1

บนของคุณviewDidLayoutSubviewsตั้งค่าเป็นestimatedItemSizeความกว้างเต็ม (เค้าโครงหมายถึงวัตถุ UICollectionViewFlowLayout):

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
    return CGSize(width: collectionView.bounds.size.width, height: 120)
}

ในเซลล์ของคุณตรวจสอบให้แน่ใจว่าข้อ จำกัด ของคุณสัมผัสทั้งด้านบนและด้านล่างของเซลล์ (รหัสต่อไปนี้ใช้การทำแผนที่เพื่อลดความซับซ้อนของการตั้งค่าข้อ จำกัด แต่คุณสามารถทำได้ด้วย NSLayoutConstraint หรือ IB หากคุณต้องการ):

constrain(self, nameLabel, valueLabel) { view, name, value in
        name.top == view.top + 10
        name.left == view.left
        name.bottom == view.bottom - 10
        value.right == view.right
        value.centerY == view.centerY
    }

Voila ตอนนี้เซลล์ของคุณจะเติบโตสูงโดยอัตโนมัติ!


0

ไม่มีโซลูชันใดที่ใช้ได้ผลสำหรับฉันเนื่องจากฉันต้องการความกว้างแบบไดนามิกเพื่อปรับระหว่างความกว้างของ iPhone

    class CustomLayoutFlow: UICollectionViewFlowLayout {
        override init() {
            super.init()
            minimumInteritemSpacing = 1 ; minimumLineSpacing = 1 ; scrollDirection = .horizontal
        }

        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            minimumInteritemSpacing = 1 ; minimumLineSpacing = 1 ; scrollDirection = .horizontal
        }

        override var itemSize: CGSize {
            set { }
            get {
                let width = (self.collectionView?.frame.width)!
                let height = (self.collectionView?.frame.height)!
                return CGSize(width: width, height: height)
            }
        }
    }

    class TextCollectionViewCell: UICollectionViewCell {
        @IBOutlet weak var textView: UITextView!

        override func prepareForReuse() {
            super.prepareForReuse()
        }
    }




    class IntroViewController: UIViewController, UITextViewDelegate, UICollectionViewDataSource, UICollectionViewDelegate, UINavigationControllerDelegate {
        @IBOutlet weak var collectionViewTopDistanceConstraint: NSLayoutConstraint!
        @IBOutlet weak var collectionViewTopDistanceConstraint: NSLayoutConstraint!
        @IBOutlet weak var collectionView: UICollectionView!
        var collectionViewLayout: CustomLayoutFlow!

        override func viewDidLoad() {
            super.viewDidLoad()

            self.collectionViewLayout = CustomLayoutFlow()
            self.collectionView.collectionViewLayout = self.collectionViewLayout
        }

        override func viewWillLayoutSubviews() {
            self.collectionViewTopDistanceConstraint.constant = UIScreen.main.bounds.height > 736 ? 94 : 70

            self.view.layoutIfNeeded()
        }
    }

0

จาก iOS 10 เรามี API ใหม่เกี่ยวกับเค้าโครงโฟลว์เพื่อทำเช่นนั้น

สิ่งที่คุณต้องทำคือการกำหนดของคุณไปยังคงใหม่flowLayout.estimatedItemSizeUICollectionViewFlowLayoutAutomaticSize

ที่มา


อืมคุณค่อนข้างแน่ใจว่าทำให้* เต็มความกว้าง ? ดังนั้นโดยพื้นฐานแล้วหนึ่งคอลัมน์?
Fattie

อาจเป็นไปได้หากคุณตั้งค่าความกว้างของ UICollectionViewCell เป็นแบบเต็มความกว้างอย่างชัดเจน
Arpit Dongre

ไม่มันไม่ได้กำหนดความกว้างเป็นความสูงเต็มและไม่สนใจค่าขนาดโดยประมาณเว้นแต่คุณจะทำตามคำตอบของ Eric ด้านบนหรือขุดด้านล่าง / ในภายหลัง
Chris Conover

ตกลงน่าเสียดายที่นี่ไม่มีส่วนเกี่ยวข้องกับปัญหาอย่างแน่นอน! เฮ้! : O
Fattie

0

AutoLayout สามารถใช้สำหรับการปรับขนาดเซลล์โดยอัตโนมัติใน CollectionView ได้ใน 2 ขั้นตอนง่ายๆ:

  1. การเปิดใช้งานการปรับขนาดเซลล์แบบไดนามิก

flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

  1. มีมุมมองคอนเทนเนอร์และตั้งค่า containerView.widthAnchor.constraint จากcollectionView(:cellForItemAt:)เพื่อจำกัดความกว้างของ contentView เป็นความกว้างของ collectionView
class ViewController: UIViewController, UICollectionViewDataSource {
    ...

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

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

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

    ....
}

เพียงเท่านี้คุณก็จะได้ผลลัพธ์ที่ต้องการ อ้างถึงส่วนสำคัญต่อไปนี้สำหรับรหัสเต็ม:

อ้างอิง / เครดิต:

ภาพหน้าจอ: ใส่คำอธิบายภาพที่นี่


-6

คุณต้องสืบทอดคลาส UICollectionViewDelegateFlowLayout บน collectionViewController ของคุณ จากนั้นเพิ่มฟังก์ชั่น:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: view.frame.width, height: 100)
}

เมื่อใช้สิ่งนั้นคุณจะมีขนาดความกว้างของความกว้างของหน้าจอ

และตอนนี้คุณมี collectionViewController ที่มีแถวเป็น tableViewController

หากคุณต้องการให้ขนาดความสูงของแต่ละเซลล์เป็นแบบไดนามิกคุณควรสร้างเซลล์ที่กำหนดเองสำหรับแต่ละเซลล์ที่คุณต้องการ


7
นี่ไม่ใช่คำตอบสำหรับคำถาม :) นั่นจะให้ความสูงคงที่ 100 นั่นคือเป็นวิธีที่โปรแกรมหนึ่งก่อนที่จะมีการจัดวางอัตโนมัติ
Fattie
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.