ऐसा लगता है कि आप जो पूछ रहे हैं, वह UICablelectViewView का उपयोग करने का एक तरीका है, जैसे कि UITableView जैसे लेआउट का उत्पादन करना। अगर यह वास्तव में आप क्या चाहते हैं, तो ऐसा करने का सही तरीका कस्टम UICollectionViewLayout उपवर्ग (शायद SBTableLayout जैसा कुछ ) के साथ है।
दूसरी ओर, यदि आप वास्तव में पूछ रहे हैं कि क्या डिफ़ॉल्ट UICollectionViewFlowLayout के साथ ऐसा करने का कोई साफ तरीका है, तो मेरा मानना है कि कोई रास्ता नहीं है। यहां तक कि iOS8 के सेल्फ-साइजिंग सेल के साथ, यह सीधा नहीं है। मौलिक समस्या, जैसा कि आप कहते हैं, यह है कि प्रवाह लेआउट की मशीनरी एक आयाम को ठीक करने और कोई अन्य प्रतिक्रिया देने का कोई रास्ता नहीं प्रदान करती है। (इसके अलावा, यदि आप कर सकते हैं, तो मल्टी-लाइन लेबल्स को आकार देने के लिए दो लेआउट पास की आवश्यकता के आसपास अतिरिक्त जटिलता होगी। यह स्व-आकार देने वाली कोशिकाओं को एक कॉल के माध्यम से सभी साइलेज को सिस्टमलैटआउटफिटिंगसाइज के साथ गणना करने के तरीके के साथ फिट नहीं हो सकता है।)
हालाँकि, यदि आप अभी भी प्रवाह लेआउट के साथ एक टेबलव्यू-जैसा लेआउट बनाना चाहते हैं, तो उन कोशिकाओं के साथ, जो अपना आकार निर्धारित करते हैं, और संग्रह के दृश्य की चौड़ाई के लिए स्वाभाविक रूप से प्रतिक्रिया करते हैं, निश्चित रूप से यह संभव है। अभी भी गड़बड़ तरीका है। मैंने इसे एक "साइज़िंग सेल" के साथ किया है, अर्थात, एक गैर-प्रदर्शित यूआईसीओलेक्टेनेशन व्यूसेल कि नियंत्रक केवल सेल आकार की गणना के लिए रखता है।
इस दृष्टिकोण के दो भाग हैं। पहला भाग संग्रह दृश्य प्रतिनिधि के लिए सही सेल आकार की गणना करने के लिए है, संग्रह दृश्य की चौड़ाई में लेने और सेल की ऊंचाई की गणना करने के लिए सेलिंग सेल का उपयोग करके।
अपने 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 बाधाओं का उपयोग करने के लिए आकार देने वाला सेल प्राप्त करना है। यह इस तरह से कठिन होना चाहिए, क्योंकि मल्टी-लाइन यूआईबेल के प्रभावी ढंग से दो-चरण लेआउट प्रक्रिया की आवश्यकता होती है। कार्य विधि में किया जाता है 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
}
(यह कोड "एडवांस्ड कलेक्शन व्यू" पर WWDC2014 सत्र के नमूना कोड से Apple नमूना कोड से अनुकूलित है।)
एक युगल नोटिस की ओर इशारा करता है। यह संपूर्ण सेल के लेआउट को बाध्य करने, लेबल की चौड़ाई की गणना करने और सेट करने के लिए लेआउटआईफाइड () का उपयोग कर रहा है। लेकिन इतना ही काफी नहीं है। मेरा मानना है कि आपको सेट करने की भी आवश्यकता है preferredMaxLayoutWidth
ताकि लेबल ऑटो लेआउट के साथ उस चौड़ाई का उपयोग करे। और इसके बाद ही आप systemLayoutSizeFittingSize
लेबल को खाते में लेते हुए इसकी ऊंचाई की गणना करने के लिए सेल का उपयोग कर सकते हैं ।
क्या मुझे यह तरीका पसंद है? नहीं!! यह बहुत जटिल लगता है, और यह दो बार लेआउट करता है। लेकिन जब तक प्रदर्शन एक मुद्दा नहीं बन जाता है, मैं रनटाइम में दो बार लेआउट का प्रदर्शन करता हूं, जबकि इसे दो बार कोड में परिभाषित करना पड़ता है, जो केवल अन्य विकल्प लगता है।
मेरी आशा है कि अंततः स्व-आकार देने वाले सेल अलग तरीके से काम करेंगे और यह सब बहुत सरल हो जाएगा।
उदाहरण परियोजना इसे काम पर दिखा रही है।
लेकिन सिर्फ स्व-आकार देने वाली कोशिकाओं का उपयोग क्यों न करें?
सिद्धांत रूप में, "स्व-आकार देने वाली कोशिकाओं" के लिए iOS8 की नई सुविधाओं को यह अनावश्यक बनाना चाहिए। यदि आपने ऑटो लेआउट (AL) के साथ एक सेल को परिभाषित किया है, तो संग्रह दृश्य को स्मार्ट होना चाहिए ताकि वह खुद को आकार दे सके और खुद को सही ढंग से बाहर कर सके। व्यवहार में, मैंने ऐसा कोई उदाहरण नहीं देखा है जिसने मल्टी-लाइन लेबल के साथ काम करने के लिए इसे प्राप्त किया हो। मुझे लगता है कि यह आंशिक रूप से है क्योंकि स्व-साइटिंग सेल तंत्र अभी भी छोटी गाड़ी है।
लेकिन मैं शर्त लगाता हूँ कि यह ज्यादातर ऑटो लेआउट और लेबल की सामान्य चाल के कारण होता है, जो यह है कि UILabels को मूल रूप से दो-चरण लेआउट प्रक्रिया की आवश्यकता होती है। यह मेरे लिए स्पष्ट नहीं है कि आप स्व-आकार देने वाली कोशिकाओं के साथ दोनों चरणों का प्रदर्शन कैसे कर सकते हैं।
और जैसा मैंने कहा, यह वास्तव में एक अलग लेआउट के लिए एक काम है। यह फ्लो लेआउट के सार का हिस्सा है, जो ऐसी चीज़ों को आकार देता है, जो एक चौड़ाई को तय करने के बजाय एक आकार देती हैं और उन्हें अपनी ऊंचाई चुनने देती हैं।
और क्या पसंद के बारे में
preferredLayoutAttributesFittingAttributes:
विधि एक रेड हेरिंग है, मुझे लगता है। यह केवल नए स्व-आकार देने वाले सेल तंत्र के साथ उपयोग किए जाने के लिए है। तो यह जवाब नहीं है क्योंकि यह तंत्र अविश्वसनीय है।
और systemlayoutSizeFittingSize के साथ क्या हो रहा है:?
आप सही हैं कि डॉक्स भ्रमित कर रहे हैं।
डॉक्स ऑन systemLayoutSizeFittingSize:
और systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority:
दोनों यह सुझाव देते हैं कि आपको केवल पास होना चाहिए UILayoutFittingCompressedSize
और UILayoutFittingExpandedSize
जैसा होना चाहिए targetSize
। हालाँकि, विधि हस्ताक्षर स्वयं, शीर्ष लेख टिप्पणियाँ, और फ़ंक्शन के व्यवहार से संकेत मिलता है कि वे targetSize
पैरामीटर के सटीक मान पर प्रतिक्रिया दे रहे हैं ।
वास्तव में, यदि आप UICollectionViewFlowLayoutDelegate.estimatedItemSize
नए स्व-आकारीय सेल तंत्र को सक्षम करने के लिए सेट करते हैं, तो यह मान लक्षित लक्ष्य के रूप में पारित हो जाता है। और UILabel.systemLayoutSizeFittingSize
जैसा लगता है ठीक वैसा ही मान लौटता है UILabel.sizeThatFits
। यह संदेहास्पद है, यह देखते हुए कि तर्क को systemLayoutSizeFittingSize
एक मोटा लक्ष्य sizeThatFits:
माना जाता है और तर्क को अधिकतम आकार का आकार माना जाता है।
और अधिक संसाधनों
हालांकि यह सोचना दुखद है कि इस तरह की नियमित आवश्यकता के लिए "शोध संसाधनों" की आवश्यकता होती है, मुझे लगता है कि यह करता है। अच्छे उदाहरण और चर्चाएँ हैं: