TL; DR: पढ़ना पसंद नहीं है? GitHub पर नमूना परियोजनाओं के लिए सीधे कूदें:
वैचारिक विवरण
नीचे दिए गए पहले 2 चरण इस बात पर ध्यान दिए बिना लागू होते हैं कि आप किन iOS संस्करणों के लिए विकास कर रहे हैं।
1. सेट अप और बाधाओं को जोड़ें
अपने UITableViewCell
उपवर्ग में, अवरोधों को जोड़ें ताकि सेल के उप-साक्षात्कार में उनके किनारों को सेल के contentView के किनारों पर पिन किया जाए (सबसे महत्वपूर्ण रूप से ऊपर और नीचे के किनारों पर)। नोट: सेल के लिए साक्षात्कार ही पिन न करें; केवल सेल के लिए contentView
! इन सबव्यू के आंतरिक सामग्री आकार को टेबल व्यू सेल के कंटेंट व्यू की ऊंचाई को सुनिश्चित करें कि कंटेंट कम्प्रेशन रेसिस्टेंस और कंटेंट हगिंग बाधाओं को प्रत्येक सबव्यू के लिए वर्टिकल डायमेंशन में हग करना आपके द्वारा जोड़े गए उच्च-प्राथमिकता वाले अवरोधों से ओवरराइड नहीं हो रहा है। ( हुह? यहाँ क्लिक करें। )
याद रखें, विचार यह है कि सेल के सामग्री साक्षात्कार को सेल के कंटेंट व्यू से लंबवत जोड़ा जाए ताकि वे "दबाव" डाल सकें और उन्हें फिट करने के लिए कंटेंट व्यू का विस्तार कर सकें। कुछ साक्षात्कारों के साथ एक उदाहरण सेल का उपयोग करते हुए, यहां आपके अवरोधों के कुछ (सभी नहीं!) का एक दृश्य चित्रण है :
आप कल्पना कर सकते हैं कि जैसा कि ऊपर के उदाहरण सेल में मल्टी-लाइन बॉडी लेबल में अधिक पाठ जोड़ा गया है, पाठ को फिट करने के लिए इसे लंबवत रूप से बढ़ने की आवश्यकता होगी, जो प्रभावी रूप से सेल को ऊंचाई में बढ़ने के लिए मजबूर करेगा। (बेशक, आपको सही तरीके से काम करने के लिए बाधाओं को ठीक से प्राप्त करने की आवश्यकता है!)
अपने बाधाओं को सही करना निश्चित रूप से गतिशील लेआउट को ऑटो लेआउट के साथ काम करने का सबसे कठिन और सबसे महत्वपूर्ण हिस्सा है। यदि आप यहाँ गलती करते हैं, तो यह सब कुछ काम करने से रोक सकता है - इसलिए अपना समय ले लो! मैं आपके अवरोधों को कोड में स्थापित करने की सलाह देता हूं क्योंकि आप जानते हैं कि वास्तव में कौन सी बाधाओं को जोड़ा जा रहा है, और जब चीजें गलत हो जाती हैं, तो डीबग करना बहुत आसान होता है। कोड में बाधाओं को जोड़ना लेआउट एंकर का उपयोग करके इंटरफ़ेस बिल्डर की तुलना में आसान और काफी अधिक शक्तिशाली हो सकता है, या गिटहब पर उपलब्ध शानदार ओपन सोर्स एपीआई में से एक हो सकता है।
- यदि आप कोड में अड़चन जोड़ रहे हैं, तो आपको
updateConstraints
अपने UITableViewCell उपवर्ग की विधि के भीतर से एक बार ऐसा करना चाहिए । ध्यान दें कि updateConstraints
एक से अधिक बार कॉल किया जा सकता है, इसलिए एक ही बाधा को एक से अधिक बार जोड़ने से बचने के updateConstraints
लिए, एक बूलियन प्रॉपर्टी के लिए एक चेक के भीतर अपने बाधा-जोड़ने वाले कोड को लपेटना सुनिश्चित करें जैसे कि didSetupConstraints
(आप अपने बाधा को चलाने के बाद हाँ में सेट करें कोड कोड एक बार)। दूसरी ओर, यदि आपके पास कोड है जो मौजूदा बाधाओं (जैसे कि constant
कुछ बाधाओं पर संपत्ति को समायोजित करना ) को अपडेट करता है , तो इसे अंदर रखें updateConstraints
लेकिन चेक के बाहर didSetupConstraints
इसलिए इसे हर बार विधि कहा जा सकता है।
2. यूनीक टेबल व्यू सेल का पुन: उपयोग पहचानकर्ता निर्धारित करें
सेल में बाधाओं के प्रत्येक अनूठे सेट के लिए, एक अद्वितीय सेल पुन: उपयोग पहचानकर्ता का उपयोग करें। दूसरे शब्दों में, यदि आपकी कोशिकाओं में एक से अधिक अद्वितीय लेआउट हैं, तो प्रत्येक अद्वितीय लेआउट को अपना पुन: उपयोग पहचानकर्ता प्राप्त करना चाहिए। (एक अच्छा संकेत जो आपको एक नए पुन: उपयोग पहचानकर्ता का उपयोग करने की आवश्यकता है, जब आपके सेल संस्करण में अलग-अलग संख्या में साक्षात्कार होते हैं, या एक अलग अंदाज में साक्षात्कार की व्यवस्था की जाती है।)
उदाहरण के लिए, यदि आप प्रत्येक सेल में एक ईमेल संदेश प्रदर्शित कर रहे हैं, तो आपके पास 4 अद्वितीय लेआउट हो सकते हैं: केवल विषय के साथ संदेश, किसी विषय और निकाय के साथ संदेश, किसी विषय के साथ संदेश और फ़ोटो अनुलग्नक, और किसी विषय के साथ संदेश, शरीर, और फोटो लगाव। प्रत्येक लेआउट को इसे प्राप्त करने के लिए पूरी तरह से अलग-अलग बाधाओं की आवश्यकता होती है, इसलिए एक बार सेल शुरू होने के बाद और इन सेल प्रकारों में से एक के लिए बाधाओं को जोड़ दिया जाता है, सेल को उस सेल प्रकार के लिए विशिष्ट अद्वितीय पुन: उपयोग करने वाला पहचानकर्ता मिलना चाहिए। इसका मतलब यह है कि जब आप पुन: उपयोग के लिए एक सेल को समाप्त करते हैं, तो बाधाएं पहले ही जोड़ दी गई हैं और उस सेल प्रकार के लिए जाने के लिए तैयार हैं।
ध्यान दें कि आंतरिक सामग्री के आकार में अंतर के कारण, समान बाधाओं (प्रकार) वाले कोशिकाओं में अभी भी अलग-अलग ऊंचाइयां हो सकती हैं! विभिन्न आकार की सामग्री के कारण अलग-अलग गणना दृश्य फ़्रेम (समान बाधाओं से हल) के साथ मौलिक रूप से अलग लेआउट (विभिन्न बाधाओं) को भ्रमित न करें।
- एक ही पुन: उपयोग पूल (यानी एक ही पुन: उपयोग पहचानकर्ता का उपयोग करें) के लिए बाधाओं के पूरी तरह से अलग सेट के साथ कोशिकाओं को न जोड़ें और फिर पुरानी बाधाओं को दूर करने और प्रत्येक छल के बाद खरोंच से नए अवरोध स्थापित करने का प्रयास करें। आंतरिक ऑटो लेआउट इंजन को बाधाओं में बड़े पैमाने पर परिवर्तन को संभालने के लिए डिज़ाइन नहीं किया गया है, और आप बड़े पैमाने पर प्रदर्शन के मुद्दों को देखेंगे।
IOS 8 के लिए - सेल्फ-सिजिंग सेल
3. सक्षम ऊँचाई अनुमान
सेल्फ-साइज़िंग टेबल व्यू सेल को सक्षम करने के लिए, आपको टेबल दृश्य की पंक्तिहाइट को UITableViewAutomaticDimension पर सेट करना होगा। आपको अनुमानितReHeight प्रॉपर्टी का मान भी असाइन करना होगा। जैसे ही ये दोनों गुण सेट होते हैं, सिस्टम पंक्ति की वास्तविक ऊंचाई की गणना करने के लिए ऑटो लेआउट का उपयोग करता है
Apple: सेल्फ-साइज़िंग टेबल व्यू सेल के साथ काम करना
IOS 8 के साथ, Apple ने बहुत से कामों को आंतरिक रूप से बदल दिया है जो पहले iOS 8 से पहले आपके द्वारा लागू किया जाना था। स्व-आकार वाले सेल तंत्र को काम करने की अनुमति देने के लिए, आपको सबसे पहले rowHeight
संपत्ति को टेबल व्यू पर स्थाई में सेट करना होगा। UITableViewAutomaticDimension
। फिर, आपको estimatedRowHeight
उदाहरण के लिए, एक गैर-अक्षीय मान पर तालिका दृश्य की संपत्ति सेट करके पंक्ति ऊंचाई अनुमान को सक्षम करने की आवश्यकता है :
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 44.0; // set to whatever your "average" cell height is
यह जो करता है वह उन कोशिकाओं की पंक्ति ऊंचाइयों के लिए एक अस्थायी अनुमान / प्लेसहोल्डर के साथ तालिका दृश्य प्रदान करता है जो अभी तक ऑनस्क्रीन नहीं हैं। फिर, जब ये सेल स्क्रीन पर स्क्रॉल करने वाले होते हैं, तो वास्तविक पंक्ति ऊंचाई की गणना की जाएगी। प्रत्येक पंक्ति के लिए वास्तविक ऊंचाई निर्धारित करने के लिए, टेबल व्यू स्वचालित रूप से प्रत्येक सेल से पूछता contentView
है कि कंटेंट व्यू की ज्ञात निश्चित चौड़ाई (जो टेबल व्यू की चौड़ाई पर आधारित है, किसी भी अतिरिक्त चीज़ों जैसे कि एक सेक्शन इंडेक्स) के आधार पर उसकी ऊंचाई कितनी होनी चाहिए। या एक्सेसरी व्यू) और ऑटो लेआउट ने आपको सेल के कंटेंट व्यू और इंटरव्यू में जोड़ा है। एक बार इस वास्तविक सेल की ऊँचाई निर्धारित हो जाने के बाद, पंक्ति के लिए पुरानी अनुमानित ऊँचाई को नई वास्तविक ऊँचाई के साथ अपडेट किया जाता है (और टेबल व्यू के कंटेंटसाइज़ / कंटेंटऑफ़सेट के किसी भी समायोजन को आपके लिए आवश्यकतानुसार बनाया जाता है)।
सामान्यतया, आपके द्वारा प्रदान किया जाने वाला अनुमान बहुत सटीक नहीं होता है - यह केवल तालिका दृश्य में स्क्रॉल संकेतक को सही ढंग से आकार देने के लिए उपयोग किया जाता है, और तालिका दृश्य आपके द्वारा गलत अनुमानों के लिए स्क्रॉल संकेतक को समायोजित करने का एक अच्छा काम करता है। स्क्रॉल सेल ऑनस्क्रीन। आपको estimatedRowHeight
संपत्ति को टेबल व्यू ( viewDidLoad
या समान) पर एक स्थिर मान पर सेट करना चाहिए जो "औसत" पंक्ति की ऊंचाई है। केवल तभी जब आपकी पंक्ति की ऊँचाई में परिवर्तनशीलता हो (जैसे परिमाण के एक क्रम से भिन्न) और आप स्क्रॉल सूचक को "जंपिंग" नोटिस करते हैं, जैसा कि आप स्क्रॉल tableView:estimatedHeightForRowAtIndexPath:
करते हैं, आपको प्रत्येक पंक्ति के लिए अधिक सटीक अनुमान वापस करने के लिए आवश्यक न्यूनतम गणना करने के लिए कार्यान्वयन को परेशान करना चाहिए ।
IOS 7 सपोर्ट के लिए (ऑटो सेल को खुद को लागू करते हुए)
3. एक लेआउट पास और सेल ऊंचाई प्राप्त करें
सबसे पहले, टेबल व्यू सेल के एक ऑफस्क्रीन इंस्टेंस को इंस्टेंट करें, प्रत्येक पुन: उपयोग करने वाले पहचानकर्ता के लिए एक उदाहरण , जिसका उपयोग कड़ाई से गणना के लिए किया जाता है। (ऑफस्क्रीन मतलब सेल रेफरेंस को व्यू कंट्रोलर पर एक प्रॉपर्टी / ivar में स्टोर किया जाता है और tableView:cellForRowAtIndexPath:
टेबल व्यू के लिए कभी भी ऑनस्क्रीन रेंडर नहीं किया जाता है।) इसके बाद, सेल को सटीक कंटेंट (जैसे टेक्स्ट, इमेज आदि) से कॉन्फ़िगर करना होगा। यदि यह तालिका दृश्य में प्रदर्शित किया जाना था, तो इसे धारण करेगा।
तुरंत इसकी subviews लेआउट करने के लिए फिर, सेल के लिए मजबूर है, और फिर उपयोग करने systemLayoutSizeFittingSize:
पर विधि UITableViewCell
के contentView
पता लगाने के लिए क्या सेल के लिए आवश्यक ऊंचाई है। UILayoutFittingCompressedSize
सेल की सभी सामग्रियों को फिट करने के लिए आवश्यक सबसे छोटे आकार को प्राप्त करने के लिए उपयोग करें । फिर ऊंचाई को tableView:heightForRowAtIndexPath:
प्रतिनिधि पद्धति से वापस किया जा सकता है ।
4. अनुमानित पंक्ति हाइट का उपयोग करें
यदि आपकी तालिका दृश्य में एक दर्जन से अधिक पंक्तियाँ हैं, तो आप पाएंगे कि ऑटो लेआउट बाधा को हल करते हुए जल्दी से मुख्य धागे को काट सकते हैं जब पहली बार तालिका दृश्य लोड हो रहा है, जैसा tableView:heightForRowAtIndexPath:
कि प्रत्येक लोड पर पहली पंक्ति में कहा जाता है ( स्क्रॉल संकेतक के आकार की गणना करने के लिए)।
IOS 7 के रूप में, आप (और बिल्कुल चाहिए) estimatedRowHeight
तालिका दृश्य पर संपत्ति का उपयोग कर सकते हैं। यह जो करता है वह उन कोशिकाओं की पंक्ति ऊंचाइयों के लिए एक अस्थायी अनुमान / प्लेसहोल्डर के साथ तालिका दृश्य प्रदान करता है जो अभी तक ऑनस्क्रीन नहीं हैं। फिर, जब ये सेल स्क्रीन पर स्क्रॉल करने वाले होते हैं, तो वास्तविक पंक्ति की ऊंचाई (कॉल करके tableView:heightForRowAtIndexPath:
) गणना की जाएगी , और वास्तविक के साथ अद्यतन की गई अनुमानित ऊंचाई।
सामान्यतया, आपके द्वारा प्रदान किया जाने वाला अनुमान बहुत सटीक नहीं होता है - यह केवल तालिका दृश्य में स्क्रॉल संकेतक को सही ढंग से आकार देने के लिए उपयोग किया जाता है, और तालिका दृश्य आपके द्वारा गलत अनुमानों के लिए स्क्रॉल संकेतक को समायोजित करने का एक अच्छा काम करता है। स्क्रॉल सेल ऑनस्क्रीन। आपको estimatedRowHeight
संपत्ति को टेबल व्यू ( viewDidLoad
या समान) पर एक स्थिर मान पर सेट करना चाहिए जो "औसत" पंक्ति की ऊंचाई है। केवल तभी जब आपकी पंक्ति की ऊँचाई में परिवर्तनशीलता हो (जैसे परिमाण के एक क्रम से भिन्न) और आप स्क्रॉल सूचक को "जंपिंग" नोटिस करते हैं, जैसा कि आप स्क्रॉल tableView:estimatedHeightForRowAtIndexPath:
करते हैं, आपको प्रत्येक पंक्ति के लिए अधिक सटीक अनुमान वापस करने के लिए आवश्यक न्यूनतम गणना करने के लिए कार्यान्वयन को परेशान करना चाहिए ।
5. (यदि आवश्यक हो) रो ऊँचाई कैशिंग जोड़ें
यदि आपने उपरोक्त सभी कार्य किए हैं और अभी भी पा रहे हैं कि बाधा को हल करते समय प्रदर्शन अस्वीकार्य रूप से धीमा है tableView:heightForRowAtIndexPath:
, तो आपको दुर्भाग्य से सेल ऊंचाइयों के लिए कुछ कैशिंग लागू करने की आवश्यकता होगी। (यह ऐप्पल के इंजीनियरों द्वारा सुझाया गया दृष्टिकोण है।) सामान्य विचार यह है कि ऑटोलेयूट इंजन को पहली बार बाधाओं को हल करने दिया जाए, फिर उस सेल के लिए गणना की गई ऊंचाई को कैश करें और उस सेल की ऊंचाई के लिए भविष्य के सभी अनुरोधों के लिए कैश्ड मान का उपयोग करें। पाठ्यक्रम की चाल यह सुनिश्चित करने के लिए है कि आप सेल के लिए कैश्ड ऊंचाई को साफ करें जब ऐसा कुछ भी होता है जो सेल की ऊंचाई को बदल सकता है - मुख्य रूप से, यह तब होगा जब उस सेल की सामग्री में परिवर्तन होता है या जब अन्य महत्वपूर्ण घटनाएं होती हैं (जैसे उपयोगकर्ता समायोजित करना डायनामिक टाइप टेक्स्ट साइज स्लाइडर)।
iOS 7 जेनेरिक सैंपल कोड (बहुत से रसदार टिप्पणियों के साथ)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Determine which reuse identifier should be used for the cell at this
// index path, depending on the particular layout required (you may have
// just one, or may have many).
NSString *reuseIdentifier = ...;
// Dequeue a cell for the reuse identifier.
// Note that this method will init and return a new cell if there isn't
// one available in the reuse pool, so either way after this line of
// code you will have a cell with the correct constraints ready to go.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
// Configure the cell with content for the given indexPath, for example:
// cell.textLabel.text = someTextForThisCell;
// ...
// Make sure the constraints have been set up for this cell, since it
// may have just been created from scratch. Use the following lines,
// assuming you are setting up constraints from within the cell's
// updateConstraints method:
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
// If you are using multi-line UILabels, don't forget that the
// preferredMaxLayoutWidth needs to be set correctly. Do it at this
// point if you are NOT doing it within the UITableViewCell subclass
// -[layoutSubviews] method. For example:
// cell.multiLineLabel.preferredMaxLayoutWidth = CGRectGetWidth(tableView.bounds);
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Determine which reuse identifier should be used for the cell at this
// index path.
NSString *reuseIdentifier = ...;
// Use a dictionary of offscreen cells to get a cell for the reuse
// identifier, creating a cell and storing it in the dictionary if one
// hasn't already been added for the reuse identifier. WARNING: Don't
// call the table view's dequeueReusableCellWithIdentifier: method here
// because this will result in a memory leak as the cell is created but
// never returned from the tableView:cellForRowAtIndexPath: method!
UITableViewCell *cell = [self.offscreenCells objectForKey:reuseIdentifier];
if (!cell) {
cell = [[YourTableViewCellClass alloc] init];
[self.offscreenCells setObject:cell forKey:reuseIdentifier];
}
// Configure the cell with content for the given indexPath, for example:
// cell.textLabel.text = someTextForThisCell;
// ...
// Make sure the constraints have been set up for this cell, since it
// may have just been created from scratch. Use the following lines,
// assuming you are setting up constraints from within the cell's
// updateConstraints method:
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
// Set the width of the cell to match the width of the table view. This
// is important so that we'll get the correct cell height for different
// table view widths if the cell's height depends on its width (due to
// multi-line UILabels word wrapping, etc). We don't need to do this
// above in -[tableView:cellForRowAtIndexPath] because it happens
// automatically when the cell is used in the table view. Also note,
// the final width of the cell may not be the width of the table view in
// some cases, for example when a section index is displayed along
// the right side of the table view. You must account for the reduced
// cell width.
cell.bounds = CGRectMake(0.0, 0.0, CGRectGetWidth(tableView.bounds), CGRectGetHeight(cell.bounds));
// Do the layout pass on the cell, which will calculate the frames for
// all the views based on the constraints. (Note that you must set the
// preferredMaxLayoutWidth on multiline UILabels inside the
// -[layoutSubviews] method of the UITableViewCell subclass, or do it
// manually at this point before the below 2 lines!)
[cell setNeedsLayout];
[cell layoutIfNeeded];
// Get the actual height required for the cell's contentView
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
// Add an extra point to the height to account for the cell separator,
// which is added between the bottom of the cell's contentView and the
// bottom of the table view cell.
height += 1.0;
return height;
}
// NOTE: Set the table view's estimatedRowHeight property instead of
// implementing the below method, UNLESS you have extreme variability in
// your row heights and you notice the scroll indicator "jumping"
// as you scroll.
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Do the minimal calculations required to be able to return an
// estimated row height that's within an order of magnitude of the
// actual height. For example:
if ([self isTallCellAtIndexPath:indexPath]) {
return 350.0;
} else {
return 40.0;
}
}
नमूना परियोजनाओं
ये परियोजनाएं UILabels में गतिशील सामग्री वाले तालिका दृश्य कोशिकाओं के कारण चर पंक्ति ऊंचाइयों के साथ तालिका विचारों के पूरी तरह से काम कर रहे उदाहरण हैं।
ज़मीरिन (C # /। NET)
यदि आप Xamarin का उपयोग कर रहे हैं, तो @KentBoogaart द्वारा लगाई गई इस नमूना परियोजना को देखें ।