UICollectionView ภายใน UITableViewCell - ความสูงแบบไดนามิก?


125

หนึ่งในหน้าจอแอปพลิเคชันของเราต้องการให้เราวางUICollectionViewไฟล์UITableViewCell. สิ่งนี้UICollectionViewจะมีจำนวนรายการแบบไดนามิกทำให้มีความสูงซึ่งต้องคำนวณแบบไดนามิกเช่นกัน UICollectionViewแต่ผมกำลังทำงานเป็นปัญหาพยายามที่จะคำนวณความสูงของที่ฝังตัว

การครอบคลุมของเราUIViewControllerถูกสร้างขึ้นในสตอรีบอร์ดและใช้ประโยชน์จากรูปแบบอัตโนมัติ แต่ฉันไม่รู้วิธีเพิ่มความสูงแบบไดนามิกUITableViewCellตามความสูงของไฟล์UICollectionView.

ใครสามารถให้คำแนะนำหรือคำแนะนำเกี่ยวกับวิธีการทำสิ่งนี้ได้บ้าง?


คุณสามารถบอกเพิ่มเติมเกี่ยวกับเลย์เอาต์ที่คุณพยายามทำให้สำเร็จได้หรือไม่? ความสูงของส่วนสูงUITableViewCellแตกต่างจากมุมมองตารางเฉียบพลันหรือไม่? คุณไม่จำเป็นต้องเลื่อนแนวตั้งทั้งในUICollectionViewและUITableView
apouche

3
ความสูงของ UITableViewCell ควรเป็นแบบไดนามิกตามความสูงของ UICollectionView ที่เป็นส่วนหนึ่งของเซลล์มุมมองตาราง เค้าโครงของ UICollectionView ของฉันคือ 4 คอลัมน์และจำนวนแถวแบบไดนามิก ดังนั้นเมื่อมี 100 รายการฉันจะมี 4 คอลัมน์และ 25 แถวใน UICollectionView ของฉัน ความสูงของเซลล์นั้น - ตามที่ระบุโดย heightForRowAtIndexPath ของ UITableView - ต้องสามารถปรับได้ตามขนาดของ UICollectionView นั้น ที่ชัดเจนกว่านี้หน่อย?
Shadowman

@Shadowman โปรดแนะนำทางออกสำหรับสถานการณ์นี้ให้ฉัน
Ravi Ojha

คำตอบ:


127

คำตอบที่ถูกต้องใช่คุณสามารถทำเช่นนี้

ฉันเจอปัญหานี้เมื่อหลายสัปดาห์ก่อน มันง่ายกว่าที่คุณคิดจริงๆ ใส่เซลล์ของคุณลงใน NIB (หรือสตอรีบอร์ด) แล้วตรึงไว้เพื่อให้การจัดวางอัตโนมัติทำงานทั้งหมด

ให้โครงสร้างต่อไปนี้:

tableView

TableViewCell

CollectionView

CollectionViewCell

CollectionViewCell

CollectionViewCell

[... จำนวนเซลล์หรือขนาดเซลล์ที่แตกต่างกัน]

วิธีแก้ปัญหาคือบอกให้เค้าโครงอัตโนมัติคำนวณขนาด collectionViewCell ก่อนจากนั้นคอลเลกชันดู contentSize และใช้เป็นขนาดของเซลล์ของคุณ นี่คือวิธีการUIViewที่ "ใช้เวทมนตร์":

-(void)systemLayoutSizeFittingSize:(CGSize)targetSize 
     withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority 
           verticalFittingPriority:(UILayoutPriority)verticalFittingPriority

คุณต้องกำหนดขนาดของ TableViewCell ที่นี่ซึ่งในกรณีของคุณคือ contentSize ของ CollectionView

CollectionViewCell

ที่CollectionViewCellคุณต้องบอกให้เซลล์จัดวางทุกครั้งที่คุณเปลี่ยนโมเดล (เช่นคุณตั้งค่า UILabel ด้วยข้อความจากนั้นเซลล์จะต้องถูกจัดวางอีกครั้ง)

- (void)bindWithModel:(id)model {
    // Do whatever you may need to bind with your data and 
    // tell the collection view cell's contentView to resize
    [self.contentView setNeedsLayout];
}
// Other stuff here...

TableViewCell

TableViewCellไม่มายากล มันมีทางออกที่จะ collectionView ของคุณช่วยให้รูปแบบอัตโนมัติสำหรับเซลล์ collectionView ใช้estimatedItemSizeของUICollectionViewFlowLayout

จากนั้นเคล็ดลับคือการกำหนดขนาดเซลล์ tableView ของคุณที่เมธอด systemLayoutSizeFittingSize ... (หมายเหตุ: iOS8 หรือใหม่กว่า)

หมายเหตุ: ฉันพยายามใช้วิธีความสูงของเซลล์ผู้รับมอบสิทธิ์ของ tableView -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPathแต่มันสายเกินไปที่ระบบเค้าโครงอัตโนมัติจะคำนวณ CollectionView contentSize และบางครั้งคุณอาจพบเซลล์ที่ปรับขนาดไม่ถูกต้อง

@implementation TableCell

- (void)awakeFromNib {
    [super awakeFromNib];
    UICollectionViewFlowLayout *flow = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;

    // Configure the collectionView
    flow.minimumInteritemSpacing = ...;

    // This enables the magic of auto layout. 
    // Setting estimatedItemSize different to CGSizeZero 
    // on flow Layout enables auto layout for collectionView cells.
    // https://developer.apple.com/videos/play/wwdc2014-226/
    flow.estimatedItemSize = CGSizeMake(1, 1);

    // Disable the scroll on your collection view
    // to avoid running into multiple scroll issues.
    [self.collectionView setScrollEnabled:NO];
}

- (void)bindWithModel:(id)model {
    // Do your stuff here to configure the tableViewCell
    // Tell the cell to redraw its contentView        
    [self.contentView layoutIfNeeded];
}

// THIS IS THE MOST IMPORTANT METHOD
//
// This method tells the auto layout
// You cannot calculate the collectionView content size in any other place, 
// because you run into race condition issues.
// NOTE: Works for iOS 8 or later
- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority verticalFittingPriority:(UILayoutPriority)verticalFittingPriority {

    // With autolayout enabled on collection view's cells we need to force a collection view relayout with the shown size (width)
    self.collectionView.frame = CGRectMake(0, 0, targetSize.width, MAXFLOAT);
    [self.collectionView layoutIfNeeded];

    // If the cell's size has to be exactly the content 
    // Size of the collection View, just return the
    // collectionViewLayout's collectionViewContentSize.

    return [self.collectionView.collectionViewLayout collectionViewContentSize];
}

// Other stuff here...

@end

TableViewController

อย่าลืมเปิดใช้งานระบบเค้าโครงอัตโนมัติสำหรับเซลล์ tableView ที่TableViewControllerของคุณ:

- (void)viewDidLoad {
    [super viewDidLoad];

    // Enable automatic row auto layout calculations        
    self.tableView.rowHeight = UITableViewAutomaticDimension;
    // Set the estimatedRowHeight to a non-0 value to enable auto layout.
    self.tableView.estimatedRowHeight = 10;

}

เครดิต: @rbarberaช่วยจัดเรียงสิ่งนี้


4
ใช่. นี้ได้ผล นี่ควรเป็นคำตอบที่ได้รับการยอมรับ
csotiriou

1
หน่วยงานใดสามารถให้รหัสตัวอย่างแก่ฉันได้หรือไม่? ฉันต้องการแสดงภาพหลายภาพในมุมมองคอลเลกชันแนวตั้งซึ่งอยู่ภายในเซลล์ tableview ..
Ravi Ojha

4
ในที่สุดสิ่งนี้ก็ใช้ได้ผลสำหรับฉัน แต่ฉันต้องทำเคล็ดลับอื่น ๆ : cell.bounds = CGRectMake(0, 0, CGRectGetWidth(tableView.bounds), 10000);นี่จะเป็นการ "จำลอง" เซลล์ขนาดยาวที่มี collectionView แบบยาวดังนั้น collectionView จะคำนวณขนาดของเซลล์ทั้งหมด มิฉะนั้น collectionView จะคำนวณเฉพาะขนาดเซลล์ที่มองเห็นได้และตั้งค่าความสูงของ talbeViewCell ผิด
ingaham

20
เมื่อตั้งค่าความสูงของเฟรมเป็นสูงสุดsystemLayoutSizeFittingSizeฉันประสบปัญหาอย่างรวดเร็วเมื่อโหลดเซลล์ใหม่แอพดูเหมือนจะค้างหลังจากไฟล์self.collectionView.layoutIfNeeded(). ฉันแก้ไขโดยตั้งค่าความสูงของเฟรมด้วย 1 แทนที่จะเป็นความสูงสูงสุด หวังว่าจะช่วยได้หากใครพบปัญหานี้
titan

6
นี่คือสิ่งที่แก้ไขสำหรับฉัน - ในsystemLayoutSizeFittingกลับลำดับของสิ่งที่แสดงในคำตอบในปัจจุบันเพื่อให้collectionView.layoutIfNeeded()รันครั้งแรกจากนั้นcollectionView.frame = CGRect.init(origin: .zero, size: CGSize.init(width: targetSize.width, height: 1))
xaphod

101

ฉันคิดว่าวิธีแก้ปัญหาของฉันง่ายกว่าที่เสนอโดย @PabloRomeu มาก

ขั้นตอนที่ 1. สร้างเต้าเสียบจากUICollectionViewถึงUITableViewCell subclassตำแหน่งที่UICollectionViewวางไว้ ปล่อยให้ชื่อจะเป็นcollectionView

ขั้นตอนที่ 2. เพิ่มใน IB เพื่อUICollectionViewจำกัด ความสูงและสร้างร้านUITableViewCell subclassด้วย collectionViewHeightให้มันชื่อจะเป็น

ขั้นตอนที่ 3. ในการtableView:cellForRowAtIndexPath:เพิ่มรหัส:

// deque a cell
cell.frame = tableView.bounds;
[cell layoutIfNeeded];
[cell.collectionView reloadData];
cell.collectionViewHeight.constant = cell.collectionView.collectionViewLayout.collectionViewContentSize.height;

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

2
ฉันได้ผล ฉันเพิ่มข้อ จำกัด สำหรับcollectionViewทุกด้านUITableViewCellและตั้งค่าtableView.estimatedRowHeight = 44;และtableView.rowHeight = UITableViewAutomaticDimension;
Igor

3
อันนี้ใช้งานได้เหมือนแชมป์ ... เรียบง่ายและมีประสิทธิภาพ ... ขอบคุณ หากสำหรับใครบางคนมันใช้งานไม่ได้อาจเป็นเพราะสาเหตุเราจำเป็นต้องผูกด้านล่างของมุมมองคอลเลกชันที่ด้านล่างของเซลล์มุมมองตาราง จากนั้นมันจะเริ่มทำงาน Happy coding .. :)
Sebin Roy

2
วิธีนี้จะใช้งานได้เมื่อปรับขนาดหน้าจอหรือไม่พูดโดยการหมุน iPad นั่นอาจจะเปลี่ยนความสูงของมุมมองคอลเลกชันและดังนั้นความสูงของเซลล์ แต่ถ้าบนหน้าจอเซลล์อาจไม่จำเป็นต้องโหลดซ้ำโดยมุมมองตารางดังนั้นอย่าเรียกเซลล์ForRowAtIndexPath: method และไม่ให้โอกาสคุณ เปลี่ยนค่าคงที่ข้อ จำกัด อาจเป็นไปได้ที่จะบังคับให้ reloadData แม้ว่า
Carl Lindberg

2
คุณได้ลองขนาดของเซลล์ collectionView ที่แตกต่างกันหรือไม่? นั่นคือปัญหาของฉัน หากคุณมีขนาดเซลล์ของ collectionView ที่แตกต่างกันมันก็ใช้ไม่ได้ ... :(
Pablo Romeu

22

ทั้งมุมมองตารางและมุมมองคอลเลกชันเป็นUIScrollViewคลาสย่อยดังนั้นจึงไม่ต้องการฝังอยู่ในมุมมองแบบเลื่อนอื่นเนื่องจากพยายามคำนวณขนาดเนื้อหาใช้เซลล์ซ้ำ ฯลฯ

ขอแนะนำให้คุณใช้เฉพาะมุมมองคอลเลคชันเพื่อวัตถุประสงค์ทั้งหมดของคุณ

คุณสามารถแบ่งเป็นส่วน ๆ และ "ปฏิบัติ" เค้าโครงบางส่วนเป็นมุมมองตารางและอื่น ๆ เป็นมุมมองคอลเล็กชัน ท้ายที่สุดไม่มีอะไรที่คุณไม่สามารถทำได้ด้วยมุมมองคอลเลกชันที่คุณสามารถทำได้ด้วยมุมมองตาราง

หากคุณมีเค้าโครงกริดพื้นฐานสำหรับ "ชิ้นส่วน" มุมมองคอลเลกชันของคุณคุณยังสามารถใช้เซลล์ตารางปกติเพื่อจัดการได้ หากคุณไม่ต้องการการสนับสนุน iOS 5 คุณควรใช้มุมมองคอลเลคชันดีกว่า


1
คุณใส่เครื่องหมายคำพูด "รักษา" ไว้เพราะคุณไม่สามารถกำหนดรูปแบบที่แตกต่างกันต่อส่วน CollectionView ได้ใช่ไหม ฉันไม่พบตัวเลือกในการกำหนดเค้าโครงที่แตกต่างกันสำหรับส่วนมุมมองคอลเลกชันต่างๆ ฉันมองข้ามบางสิ่งไปหรือคุณกำลังพูดถึงการตอบสนองที่แตกต่างจาก 'layoutAttributesForItemAtIndexPath' สำหรับส่วนต่างๆในคลาสย่อยที่กำหนดเองของ UICollectionViewLayout
alex da franca

ใช่ -> คุณกำลังพูดถึงการตอบสนองที่แตกต่างกันlayoutAttributesForItemAtIndexPathสำหรับส่วนต่างๆในคลาสย่อยที่กำหนดเองของฉันเองUICollectionViewLayoutหรือไม่?
ริเวร่า

2
@Rivera คำตอบของคุณสมเหตุสมผลที่สุดและถูกต้อง ฉันได้อ่านคำแนะนำนี้ในหลาย ๆ ที่ คุณช่วยแชร์ลิงก์ไปยังตัวอย่างหรือแนะนำวิธีการทำสิ่งนั้นให้สำเร็จหรืออย่างน้อยก็คำแนะนำบางส่วน TIA
thesummersign

3
คำตอบของคุณถือว่าคุณเริ่มต้นตั้งแต่ต้นและยังไม่มีตารางมุมมองที่ซับซ้อนขนาดใหญ่ที่คุณต้องปรับให้เหมาะสม คำถามที่ถามโดยเฉพาะเกี่ยวกับการใส่คอลเลกชันในมุมมองตาราง IMO คำตอบของคุณไม่ใช่ "คำตอบ"
xaphod

2
นี่เป็นคำตอบที่ไม่ดี การมีมุมมองคอลเลกชันภายในมุมมองตารางเป็นเรื่องปกติที่ต้องทำเกือบทุกแอปก็ทำเช่นนั้น
crashhoverride777

10

คำตอบของ Pablo Romeu ด้านบน ( https://stackoverflow.com/a/33364092/2704206 ) ช่วยฉันอย่างมากเกี่ยวกับปัญหาของฉัน อย่างไรก็ตามฉันต้องทำบางสิ่งที่แตกต่างออกไปเพื่อให้สิ่งนี้ใช้ได้กับปัญหาของฉัน ก่อนอื่นฉันไม่ต้องโทรlayoutIfNeeded()บ่อย ฉันต้องเรียกมันจากcollectionViewในsystemLayoutSizeFittingฟังก์ชันเท่านั้น

ประการที่สองฉันมีข้อ จำกัด การจัดวางอัตโนมัติในมุมมองคอลเลกชันของฉันในเซลล์มุมมองตารางเพื่อให้มีช่องว่างภายใน ดังนั้นฉันต้องลบระยะขอบนำหน้าและส่วนท้ายออกจากtargetSize.widthเมื่อตั้งค่าcollectionView.frameความกว้าง ฉันต้องเพิ่มระยะขอบบนและล่างให้กับCGSizeความสูงของค่าส่งคืนด้วย

เพื่อให้ได้ค่าคงที่ของข้อ จำกัด เหล่านี้ฉันมีตัวเลือกในการสร้างร้านค้าตามข้อ จำกัด ฮาร์ดโค้ดค่าคงที่หรือค้นหาโดยใช้ตัวระบุ ฉันตัดสินใจใช้ตัวเลือกที่สามเพื่อให้คลาสเซลล์มุมมองตารางที่กำหนดเองของฉันใช้ซ้ำได้อย่างง่ายดาย ในท้ายที่สุดนี่คือทุกสิ่งที่ฉันต้องการเพื่อให้มันใช้งานได้:

class CollectionTableViewCell: UITableViewCell {

    // MARK: -
    // MARK: Properties
    @IBOutlet weak var collectionView: UICollectionView! {
        didSet {
            collectionViewLayout?.estimatedItemSize = CGSize(width: 1, height: 1)
            selectionStyle = .none
        }
    }

    var collectionViewLayout: UICollectionViewFlowLayout? {
        return collectionView.collectionViewLayout as? UICollectionViewFlowLayout
    }

    // MARK: -
    // MARK: UIView functions
    override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
        collectionView.layoutIfNeeded()

        let topConstraintConstant = contentView.constraint(byIdentifier: "topAnchor")?.constant ?? 0
        let bottomConstraintConstant = contentView.constraint(byIdentifier: "bottomAnchor")?.constant ?? 0
        let trailingConstraintConstant = contentView.constraint(byIdentifier: "trailingAnchor")?.constant ?? 0
        let leadingConstraintConstant = contentView.constraint(byIdentifier: "leadingAnchor")?.constant ?? 0

        collectionView.frame = CGRect(x: 0, y: 0, width: targetSize.width - trailingConstraintConstant - leadingConstraintConstant, height: 1)

        let size = collectionView.collectionViewLayout.collectionViewContentSize
        let newSize = CGSize(width: size.width, height: size.height + topConstraintConstant + bottomConstraintConstant)
        return newSize
    }
}

ในฐานะที่เป็นฟังก์ชันตัวช่วยในการดึงข้อ จำกัด ด้วยตัวระบุฉันจึงเพิ่มส่วนขยายต่อไปนี้:

extension UIView {
    func constraint(byIdentifier identifier: String) -> NSLayoutConstraint? {
        return constraints.first(where: { $0.identifier == identifier })
    }
}

หมายเหตุ: คุณจะต้องตั้งค่าตัวระบุตามข้อ จำกัด เหล่านี้ในสตอรีบอร์ดของคุณหรือที่ใดก็ตามที่สร้างขึ้น เว้นแต่พวกเขาจะมีค่าคงที่ 0 ก็ไม่สำคัญ เช่นเดียวกับในคำตอบของ Pablo คุณจะต้องใช้UICollectionViewFlowLayoutเป็นเค้าโครงสำหรับมุมมองคอลเลกชันของคุณ สุดท้ายตรวจสอบให้แน่ใจว่าคุณเชื่อมโยงcollectionViewIBOutlet กับสตอรีบอร์ดของคุณ

ด้วยเซลล์มุมมองตารางแบบกำหนดเองด้านบนตอนนี้ฉันสามารถ subclass ในเซลล์มุมมองตารางอื่น ๆ ที่ต้องการมุมมองคอลเลกชันและให้ใช้UICollectionViewDelegateFlowLayoutและUICollectionViewDataSourceโปรโตคอล หวังว่านี่จะเป็นประโยชน์กับคนอื่น ๆ !


5

ฉันอ่านคำตอบทั้งหมด ดูเหมือนว่าจะให้บริการทุกกรณี

override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
        collectionView.layoutIfNeeded()
        collectionView.frame = CGRect(x: 0, y: 0, width: targetSize.width , height: 1)
        return collectionView.collectionViewLayout.collectionViewContentSize
}

3

อีกทางเลือกหนึ่งของโซลูชันของ Pablo Romeu คือการปรับแต่ง UICollectionView เองแทนที่จะทำงานในเซลล์มุมมองตาราง

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

สร้างคลาสย่อยของ UICollectionView และแทนที่เมธอดต่อไปนี้

override func intrinsicContentSize() -> CGSize {
    self.layoutIfNeeded()

    var size = super.contentSize
    if size.width == 0 || size.height == 0 {
        // return a default size
        size = CGSize(width: 600, height:44)
    }

    return size
 }

override func reloadData() {
    super.reloadData()
    self.layoutIfNeeded()
    self.invalidateIntrinsicContentSize()
}

(คุณควรแทนที่วิธีการที่เกี่ยวข้อง: reloadSections, reloadItemsAtIndexPaths ในลักษณะเดียวกับ reloadData ())

การเรียก layoutIfNeeded บังคับให้มุมมองคอลเลกชันคำนวณขนาดเนื้อหาใหม่ซึ่งสามารถใช้เป็นขนาดที่แท้จริงใหม่ได้

นอกจากนี้คุณต้องจัดการกับการเปลี่ยนแปลงขนาดมุมมองอย่างชัดเจน (เช่นเมื่อหมุนอุปกรณ์) ในตัวควบคุมมุมมองตาราง

    override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
{
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
    dispatch_async(dispatch_get_main_queue()) {
        self.tableView.reloadData()
    }
}

พี่ช่วยช่วยแก้ปัญหาของฉันได้ไหมstackoverflow.com/questions/44650058/…
พฤษภาคม Phyu

3

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

ในcellForRow:atIndexPathมุมมองตารางฉันทำสิ่งต่อไปนี้:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    //do dequeue stuff
    //initialize the the collection view data source with the data
    cell.frame = CGRect.zero
    cell.layoutIfNeeded()
    return cell
}

ฉันคิดว่าสิ่งที่เกิดขึ้นที่นี่คือฉันบังคับให้เซลล์มุมมองตารางปรับความสูงหลังจากคำนวณความสูงของมุมมองคอลเลคชันแล้ว (หลังจากระบุวันที่ collectionView ให้กับแหล่งข้อมูล)


2

ฉันจะใส่วิธีการคงที่ในคลาสมุมมองคอลเลกชันที่จะส่งคืนขนาดตามเนื้อหาที่จะมี จากนั้นใช้วิธีนั้นในการheightForRowAtIndexPathส่งคืนขนาดที่เหมาะสม

โปรดทราบว่าคุณจะได้รับพฤติกรรมแปลก ๆ เมื่อคุณฝัง viewControllers ประเภทนี้ ฉันทำครั้งเดียวและมีปัญหาเกี่ยวกับหน่วยความจำแปลก ๆ ที่ฉันไม่เคยได้รับ


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

2

บางทีตัวแปรของฉันอาจมีประโยชน์ ฉันกำลังตัดสินใจงานนี้ในช่วงสองชั่วโมงที่ผ่านมา ฉันไม่ได้แสร้งทำเป็นว่ามันถูกต้องหรือดีที่สุด 100% แต่ทักษะของฉันยังน้อยมากและฉันต้องการฟังความคิดเห็นจากผู้เชี่ยวชาญ ขอบคุณ. หมายเหตุสำคัญอย่างหนึ่ง: สิ่งนี้ใช้ได้กับตารางแบบคงที่ซึ่งระบุโดยงานปัจจุบันของฉัน ดังนั้นทุกการใช้งานผมเป็นviewWillLayoutSubviewsของtableView และอื่น ๆ อีกเล็กน้อย

private var iconsCellHeight: CGFloat = 500 

func updateTable(table: UITableView, withDuration duration: NSTimeInterval) {
    UIView.animateWithDuration(duration, animations: { () -> Void in
        table.beginUpdates()
        table.endUpdates()
    })
}

override func viewWillLayoutSubviews() {
    if let iconsCell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 1)) as? CategoryCardIconsCell {
        let collectionViewContentHeight = iconsCell.iconsCollectionView.contentSize.height
        if collectionViewContentHeight + 17 != iconsCellHeight {
            iconsCellHeight = collectionViewContentHeight + 17
            updateTable(tableView, withDuration: 0.2)
        }
    }
}

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    switch (indexPath.section, indexPath.row) {
        case ...
        case (1,0):
            return iconsCellHeight
        default:
            return tableView.rowHeight
    }
}
  1. ฉันรู้ว่า collectionView อยู่ในแถวแรกของส่วนที่สอง
  2. ให้ความสูงของแถวคือ 17 หน้า ใหญ่กว่าความสูงของเนื้อหา
  3. iconsCellHeight เป็นตัวเลขสุ่มเมื่อโปรแกรมเริ่มทำงาน (ฉันรู้ว่าในรูปแบบแนวตั้งจะต้องเป็น 392 แต่ก็ไม่สำคัญ) หากเนื้อหาของ collectionView + 17 ไม่เท่ากับจำนวนนี้ให้เปลี่ยนค่า ครั้งต่อไปในสถานการณ์นี้เงื่อนไขจะให้เป็นเท็จ
  4. หลังจากอัปเดต tableView ทั้งหมด ในกรณีของฉันมันเป็นการรวมกันของสองการดำเนินการ (สำหรับการอัปเดตการขยายแถวที่ดี)
  5. และแน่นอนใน heightForRowAtIndexPath เพิ่มหนึ่งแถวในโค้ด

2

วิธีที่ง่ายที่สุดที่ฉันได้คิดขึ้นมาจนถึงตอนนี้ให้เครดิตกับคำตอบของ @igor ด้านบน

ในคลาส tableviewcell ของคุณเพียงแค่ใส่สิ่งนี้

override func layoutSubviews() {
    self.collectionViewOutlet.constant = self.postPoll.collectionViewLayout.collectionViewContentSize.height
}

และแน่นอนเปลี่ยน collectionviewoutlet กับร้านของคุณในคลาสของเซลล์


1
ความสูงของเซลล์คำนวณไม่ถูกต้อง
Nik Kov

2

ฉันได้รับแนวคิดจาก@Igorโพสต์และใช้เวลากับสิ่งนี้เพื่อโครงการของฉันอย่างรวดเร็ว

ผ่านสิ่งนี้ในไฟล์

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    //do dequeue stuff
    cell.frame = tableView.bounds
    cell.layoutIfNeeded()
    cell.collectionView.reloadData()
    cell.collectionView.heightAnchor.constraint(equalToConstant: cell.collectionView.collectionViewLayout.collectionViewContentSize.height)
    cell.layoutIfNeeded()
    return cell
}

เพิ่มเติม: หากคุณเห็น UICollectionView ของคุณกระตุกเมื่อโหลดเซลล์

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {       
  //do dequeue stuff
  cell.layer.shouldRasterize = true
  cell.layer.rasterizationScale = UIScreen.main.scale
  return cell
}

0

โซลูชันของ Pablo ทำงานได้ไม่ดีสำหรับฉันฉันมีเอฟเฟกต์ภาพแปลก ๆ (collectionView ปรับไม่ถูกต้อง)

สิ่งที่ทำงานคือการปรับข้อ จำกัด ความสูงของ collectionView (เป็น NSLayoutConstraint) เพื่อ collectionView contentSize layoutSubviews()ระหว่าง นี่คือวิธีการที่เรียกว่าเมื่อใช้การจัดวางอัตโนมัติกับเซลล์

// Constraint on the collectionView height in the storyboard. Priority set to 999.
@IBOutlet weak var collectionViewHeightConstraint: NSLayoutConstraint!


// Method called by autolayout to layout the subviews (including the collectionView).
// This is triggered with 'layoutIfNeeded()', or by the viewController
// (happens between 'viewWillLayoutSubviews()' and 'viewDidLayoutSubviews()'.
override func layoutSubviews() {

    collectionViewHeightConstraint.constant = collectionView.contentSize.height
    super.layoutSubviews()
}

// Call `layoutIfNeeded()` when you update your UI from the model to trigger 'layoutSubviews()'
private func updateUI() {
    layoutIfNeeded()
}

-3

ใน UITableViewDelegate ของคุณ:

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return ceil(itemCount/4.0f)*collectionViewCellHeight;
}

แทนที่ itemCount และ CollectionViewCellHeight ด้วยค่าจริง หากคุณมีอาร์เรย์ของอาร์เรย์ itemCount อาจเป็น:

self.items[indexPath.row].count

หรืออะไรก็ได้.


ฉันคิดว่าคำถามหลักคือวิธีการคำนวณcollectionViewCellHeight ก่อนที่จะแสดงผล
thesummersign

-3

1. สร้างเซลล์จำลอง
2. ใช้เมธอด collectionViewContentSize บน UICollectionViewLayout ของ UICollectionView โดยใช้ข้อมูลปัจจุบัน


มันน่าจะเป็นคำตอบที่ดีที่สุด ... เนื่องจากไม่มีความเป็นไปได้ที่จะตั้งค่าความสูงของเซลล์ด้วย 'uicollectionview' โดยไม่ต้องใส่เนื้อหาลงในเซลล์จำลองรับความสูงแล้วตั้งค่าอีกครั้งเป็นเซลล์ที่เหมาะสม
BartłomiejSemańczyk

ฉันจะใช้วิธีนั้นได้อย่างไร
xtrinch

เพิ่มตัวอย่าง
Nik Kov

-5

คุณสามารถคำนวณความสูงของคอลเลกชันขึ้นอยู่กับคุณสมบัติของมันเช่นitemSize, sectionInset, minimumLineSpacing, minimumInteritemSpacingถ้าคุณcollectionViewCellมีเส้นขอบของกฎ

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