ดูเหมือนสิ่งที่คุณกำลังขอคือวิธีใช้ UICollectionView เพื่อสร้างเค้าโครงเช่น UITableView หากนั่นคือสิ่งที่คุณต้องการจริงๆวิธีที่ถูกต้องคือการใช้คลาสย่อย UICollectionViewLayout ที่กำหนดเอง (อาจจะคล้าย ๆSBTableLayout )
ในทางกลับกันถ้าคุณถามจริงๆว่ามีวิธีที่สะอาดในการทำเช่นนี้กับ UICollectionViewFlowLayout เริ่มต้นหรือไม่ฉันเชื่อว่าไม่มีทาง แม้จะมีเซลล์ปรับขนาดตัวเองของ iOS8 แต่ก็ไม่ตรงไปตรงมา ปัญหาพื้นฐานอย่างที่คุณพูดคือเครื่องจักรของผังการไหลไม่มีทางแก้ไขมิติหนึ่งและปล่อยให้อีกมิติตอบสนอง (นอกจากนี้แม้ว่าคุณจะทำได้ แต่ก็จะมีความซับซ้อนเพิ่มเติมเกี่ยวกับการต้องใช้เลย์เอาต์สองแบบเพื่อปรับขนาดเลเบลหลายบรรทัดซึ่งอาจไม่เหมาะกับวิธีการที่เซลล์ปรับขนาดด้วยตนเองต้องการคำนวณขนาดทั้งหมดผ่านการเรียกใช้ systemLayoutSizeFittingSize เพียงครั้งเดียว)
อย่างไรก็ตามหากคุณยังคงต้องการสร้างเค้าโครงเหมือนมุมมองตารางด้วยเค้าโครงโฟลว์โดยมีเซลล์ที่กำหนดขนาดของตัวเองและตอบสนองตามธรรมชาติตามความกว้างของมุมมองคอลเลกชันแน่นอนว่าเป็นไปได้ ยังมีวิธีที่ยุ่งเหยิง ฉันได้ทำมันด้วย "เซลล์ปรับขนาด" นั่นคือ UICollectionViewCell ที่ไม่แสดงซึ่งคอนโทรลเลอร์จะเก็บไว้สำหรับคำนวณขนาดเซลล์เท่านั้น
แนวทางนี้มีสองส่วน ส่วนแรกมีไว้สำหรับผู้รับมอบสิทธิ์มุมมองคอลเลกชันในการคำนวณขนาดเซลล์ที่ถูกต้องโดยใช้ความกว้างของมุมมองคอลเลกชันและใช้เซลล์ปรับขนาดเพื่อคำนวณความสูงของเซลล์
ใน UICollectionViewDelegateFlowLayout ของคุณคุณใช้วิธีการดังนี้:
func collectionView(collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize
{
// NOTE: here is where we say we want cells to use the width of the collection view
let requiredWidth = collectionView.bounds.size.width
// NOTE: here is where we ask our sizing cell to compute what height it needs
let targetSize = CGSize(width: requiredWidth, height: 0)
/// NOTE: populate the sizing cell's contents so it can compute accurately
self.sizingCell.label.text = items[indexPath.row]
let adequateSize = self.sizingCell.preferredLayoutSizeFittingSize(targetSize)
return adequateSize
}
สิ่งนี้จะทำให้มุมมองคอลเลกชันตั้งค่าความกว้างของเซลล์ตามมุมมองคอลเลกชันที่แนบมา แต่จากนั้นขอให้เซลล์ปรับขนาดคำนวณความสูง
ส่วนที่สองคือการทำให้เซลล์ปรับขนาดเพื่อใช้ข้อ จำกัด AL ของตัวเองเพื่อคำนวณความสูง สิ่งนี้อาจยากกว่าที่ควรจะเป็นเนื่องจากวิธีการที่มีประสิทธิภาพของ UILabel แบบหลายบรรทัดต้องใช้กระบวนการจัดวางแบบสองขั้นตอน งานเสร็จสิ้นในวิธีการpreferredLayoutSizeFittingSize
ซึ่งเป็นดังนี้:
/*
Computes the size the cell will need to be to fit within targetSize.
targetSize should be used to pass in a width.
the returned size will have the same width, and the height which is
calculated by Auto Layout so that the contents of the cell (i.e., text in the label)
can fit within that width.
*/
func preferredLayoutSizeFittingSize(targetSize:CGSize) -> CGSize {
// save original frame and preferredMaxLayoutWidth
let originalFrame = self.frame
let originalPreferredMaxLayoutWidth = self.label.preferredMaxLayoutWidth
// assert: targetSize.width has the required width of the cell
// step1: set the cell.frame to use that width
var frame = self.frame
frame.size = targetSize
self.frame = frame
// step2: layout the cell
self.setNeedsLayout()
self.layoutIfNeeded()
self.label.preferredMaxLayoutWidth = self.label.bounds.size.width
// assert: the label's bounds and preferredMaxLayoutWidth are set to the width required by the cell's width
// step3: compute how tall the cell needs to be
// this causes the cell to compute the height it needs, which it does by asking the
// label what height it needs to wrap within its current bounds (which we just set).
let computedSize = self.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
// assert: computedSize has the needed height for the cell
// Apple: "Only consider the height for cells, because the contentView isn't anchored correctly sometimes."
let newSize = CGSize(width:targetSize.width,height:computedSize.height)
// restore old frame and preferredMaxLayoutWidth
self.frame = originalFrame
self.label.preferredMaxLayoutWidth = originalPreferredMaxLayoutWidth
return newSize
}
(โค้ดนี้ดัดแปลงมาจากโค้ดตัวอย่างของ Apple จากโค้ดตัวอย่างของเซสชัน WWDC2014 ใน "Advanced Collection View")
จุดสังเกตสองสามข้อ โดยใช้ layoutIfNeeded () เพื่อบังคับเลย์เอาท์ของทั้งเซลล์เพื่อคำนวณและกำหนดความกว้างของป้ายกำกับ แต่นั่นยังไม่เพียงพอ ฉันเชื่อว่าคุณต้องตั้งค่าด้วยpreferredMaxLayoutWidth
เพื่อให้ป้ายกำกับใช้ความกว้างนั้นกับการออกแบบอัตโนมัติ จากนั้นคุณสามารถใช้systemLayoutSizeFittingSize
เพื่อให้เซลล์คำนวณความสูงในขณะที่คำนึงถึงป้ายกำกับ
ฉันชอบแนวทางนี้หรือไม่? ไม่มี !! รู้สึกว่าซับซ้อนเกินไปและจะจัดวางสองครั้ง แต่ตราบใดที่ประสิทธิภาพไม่กลายเป็นปัญหาฉันควรใช้เลย์เอาต์สองครั้งที่รันไทม์แทนที่จะต้องกำหนดโค้ดสองครั้งซึ่งดูเหมือนจะเป็นทางเลือกอื่นเท่านั้น
ความหวังของฉันคือในที่สุดเซลล์ปรับขนาดตัวเองจะทำงานแตกต่างกันและทั้งหมดนี้จะง่ายขึ้นมาก
ตัวอย่างโครงการที่แสดงในที่ทำงาน
แต่ทำไมไม่ใช้เซลล์ปรับขนาดตัวเองล่ะ?
ตามทฤษฎีแล้วสิ่งอำนวยความสะดวกใหม่ของ iOS8 สำหรับ "เซลล์ที่ปรับขนาดได้เอง" ควรทำให้สิ่งนี้ไม่จำเป็น หากคุณได้กำหนดเซลล์ด้วยโครงร่างอัตโนมัติ (AL) มุมมองคอลเลคชันควรฉลาดพอที่จะปล่อยให้มีขนาดและจัดวางได้อย่างถูกต้อง ในทางปฏิบัติฉันไม่เห็นตัวอย่างใด ๆ ที่ทำให้สามารถใช้งานกับป้ายกำกับหลายบรรทัดได้ ผมคิดว่านี่คือส่วนหนึ่งเป็นเพราะกลไกของเซลล์ตัวเองขนาดยังคงเป็นรถ
แต่ฉันพนันได้เลยว่าส่วนใหญ่เป็นเพราะความยุ่งยากตามปกติของเค้าโครงอัตโนมัติและป้ายกำกับซึ่งก็คือ UILabels ต้องการกระบวนการจัดวางแบบสองขั้นตอนโดยทั่วไป ยังไม่ชัดเจนสำหรับฉันว่าคุณสามารถดำเนินการทั้งสองขั้นตอนด้วยเซลล์ปรับขนาดตัวเองได้อย่างไร
และอย่างที่บอกว่านี่เป็นงานสำหรับเค้าโครงที่แตกต่างกันจริงๆ เป็นส่วนหนึ่งของสาระสำคัญของเค้าโครงโฟลว์ที่วางตำแหน่งของสิ่งต่างๆที่มีขนาดแทนที่จะแก้ไขความกว้างและให้พวกเขาเลือกความสูง
แล้วที่ต้องการคืออะไร?
preferredLayoutAttributesFittingAttributes:
วิธีเป็นปลาชนิดหนึ่งสีแดงผมคิดว่า นั่นคือจะใช้กับกลไกเซลล์ปรับขนาดตัวเองใหม่เท่านั้น นี่ไม่ใช่คำตอบตราบใดที่กลไกนั้นเชื่อถือไม่ได้
และเกิดอะไรขึ้นกับ systemlayoutSizeFittingSize :?
คุณคิดถูกแล้วที่เอกสารสับสน
เอกสารsystemLayoutSizeFittingSize:
และsystemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority:
ทั้งคู่แนะนำว่าคุณควรผ่านUILayoutFittingCompressedSize
และUILayoutFittingExpandedSize
เป็นไฟล์targetSize
. อย่างไรก็ตามลายเซ็นเมธอดเองความคิดเห็นส่วนหัวและลักษณะการทำงานของฟังก์ชันระบุว่าพวกเขากำลังตอบสนองต่อค่าที่แน่นอนของtargetSize
พารามิเตอร์
ในความเป็นจริงหากคุณตั้งค่าUICollectionViewFlowLayoutDelegate.estimatedItemSize
เพื่อเปิดใช้งานกลไกการปรับขนาดเซลล์ด้วยตนเองค่านั้นจะถูกส่งผ่านเป็น targetSize และดูเหมือนว่าจะกลับค่าเดียวกันกับUILabel.systemLayoutSizeFittingSize
UILabel.sizeThatFits
สิ่งนี้น่าสงสัยเนื่องจากว่าอาร์กิวเมนต์ที่systemLayoutSizeFittingSize
ควรจะเป็นเป้าหมายคร่าวๆและอาร์กิวเมนต์sizeThatFits:
ควรมีขนาด จำกัด สูงสุด
แหล่งข้อมูลเพิ่มเติม
แม้ว่าจะเป็นเรื่องน่าเศร้าที่คิดว่าข้อกำหนดประจำเช่นนี้ควรต้องการ "แหล่งข้อมูลการวิจัย" แต่ฉันคิดว่ามันเป็น ตัวอย่างและการอภิปรายที่ดี ได้แก่ :