क्या आप चयनित होने पर UITableViewCell पर ऊंचाई बदल सकते हैं?


393

मैं UITableViewअपने iPhone ऐप में उपयोग कर रहा हूं , और मेरे पास उन लोगों की सूची है जो एक समूह से संबंधित हैं। मैं इसे पसंद करूंगा ताकि जब उपयोगकर्ता किसी विशेष व्यक्ति (इस प्रकार सेल का चयन) पर क्लिक करे, तो सेल उस व्यक्ति के गुणों के संपादन के लिए कई UI नियंत्रणों को प्रदर्शित करने के लिए ऊंचाई में बढ़ता है।

क्या यह संभव है?

जवाबों:


879

मैं एक साइड-इफ़ेक्ट के लिए वास्तव में एक सरल प्रभाव के रूप में एक UITableViewI पर काम कर रहा था .....

सेल की ऊँचाई को एक चर में स्टोर करें जो मूल ऊँचाई को सामान्य रूप से रिपोर्ट करता है tableView: heightForRowAtIndexPath:, फिर जब आप ऊँचाई परिवर्तन को चेतन करना चाहते हैं, तो बस चर का मान बदलें और इसे कॉल करें ...

[tableView beginUpdates];
[tableView endUpdates];

आप पाएंगे कि यह एक पूर्ण पुनः लोड नहीं करता है, लेकिन UITableViewयह जानने के लिए पर्याप्त है कि यह कोशिकाओं को फिर से बनाना है, सेल के लिए नई ऊंचाई मान को हथियाने .... और क्या लगता है? यह आपके लिए परिवर्तन को दर्शाता है। मिठाई।

मेरे पास मेरे ब्लॉग पर अधिक विस्तृत विवरण और पूर्ण कोड नमूने हैं ... चेतन यूआईटेबल व्यू सेल हाइट चेंज


6
ये जबरदस्त है। लेकिन क्या कोई ऐसा तरीका है जिससे हम तालिका की एनीमेशन गति को नियंत्रित कर सकते हैं?
जोश काहेन

7
यह काम करता है, लेकिन अगर मैं एक सेल को 44 से 74 तक कहता हूं और फिर इसे फिर से 44 से छोटा कर देता हूं तो विभाजक रेखा पूरी तरह से अजीब हो जाती है। क्या कोई इसकी पुष्टि कर सकता है?
प्लैटजेन

46
यह एक विचित्र समाधान है, लेकिन यह वही है जो Apple WWDC 2010 के "मास्टरींग टेबल व्यू" सत्र में भी सुझाता है। मैं इसे दस्तावेज़ में जोड़ने पर बग रिपोर्ट दर्ज करने जा रहा हूं क्योंकि मैंने अभी लगभग 2 घंटे का शोध किया है।
bpapa

5
मैंने इस समाधान की कोशिश की है और यह केवल कभी-कभी काम करता है, जब आप एक सेल दबाते हैं तो काम करने की 50% संभावना होती है। किसी के पास एक ही बग है? इसका कारण iOS7 है?
जोन कार्डोना

7
अब यह आधिकारिक दस्तावेज में भी लिखा गया है: You can also use this method followed by the endUpdates method to animate the change in the row heights without reloading the cell. developer.apple.com/library/ios/documentation/UIKit/Reference/…
Jaroslav

63

मुझे साइमन ली का जवाब पसंद है। मैंने वास्तव में उस पद्धति की कोशिश नहीं की थी, लेकिन ऐसा लगता है कि यह सूची में सभी कोशिकाओं के आकार को बदल देगा। मैं सिर्फ उस सेल के बदलने की उम्मीद कर रहा था जो टैप की गई है। मैंने थोड़े ही अंतर के साथ साइमन की तरह काम किया। यह चयनित होने पर सेल का रूप बदल देगा। और यह चेतन करता है। बस इसे करने का एक और तरीका है।

वर्तमान चयनित सेल इंडेक्स के लिए मान रखने के लिए एक इंट बनाएं:

int currentSelection;

फिर:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    int row = [indexPath row];
    selectedNumber = row;
    [tableView beginUpdates];
    [tableView endUpdates];
}

फिर:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    if ([indexPath row] == currentSelection) {
        return  80;
    }
    else return 40;


}

मुझे यकीन है कि आप tableView: cellForRowAtIndexPath में समान परिवर्तन कर सकते हैं: सेल के प्रकार को बदलने के लिए या सेल के लिए xib फ़ाइल लोड करने के लिए भी।

इस तरह, CurrentSelection 0. पर शुरू होगा। यदि आपको डिफ़ॉल्ट रूप से चयनित दिखने के लिए सूची का पहला सेल (इंडेक्स 0 पर) नहीं चाहिए, तो आपको समायोजन करने की आवश्यकता होगी।


2
मेरी पोस्ट से जुड़े कोड की जांच करें, मैंने ठीक यही किया, चयनित होने पर सेल के लिए ऊंचाई दोगुनी कर दी। :)
साइमन ली

8
"मैंने वास्तव में उस तरीके की कोशिश नहीं की थी, लेकिन ऐसा लगता है कि यह सूची के सभी कोशिकाओं के आकार को बदल देगा" - फिर आप बहुत मुश्किल नहीं दिखे।
जेमी

13
वर्तमान चयन पहले से tableView.indexPathForSelectedRow में संग्रहीत है।
निक

22

चयनित सेल का ट्रैक रखने के लिए एक संपत्ति जोड़ें

@property (nonatomic) int currentSelection;

यह (उदाहरण के लिए) में एक प्रहरी मूल्य पर सेट करें, यह viewDidLoadसुनिश्चित करने के लिए कि UITableView'सामान्य' स्थिति में शुरू होता है

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    //sentinel
    self.currentSelection = -1;
}

में heightForRowAtIndexPathआप ऊंचाई सेट कर सकते हैं आप चयनित सेल के लिए चाहते हैं

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    int rowHeight;
    if ([indexPath row] == self.currentSelection) {
        rowHeight = self.newCellHeight;
    } else rowHeight = 57.0f;
    return rowHeight;
}

यदि didSelectRowAtIndexPathआप वर्तमान चयन को सहेजते हैं और यदि आवश्यक हो, तो एक गतिशील ऊंचाई बचा सकते हैं

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
        // do things with your cell here

        // set selection
        self.currentSelection = indexPath.row;
        // save height for full text label
        self.newCellHeight = cell.titleLbl.frame.size.height + cell.descriptionLbl.frame.size.height + 10;

        // animate
        [tableView beginUpdates];
        [tableView endUpdates];
    }
}

में didDeselectRowAtIndexPathप्रहरी मूल्य के लिए चयन सूचकांक वापस सेट और सामान्य रूप के लिए सेल वापस चेतन

- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {       
        // do things with your cell here

        // sentinel
        self.currentSelection = -1;

        // animate
        [tableView beginUpdates];
        [tableView endUpdates];
    }
}

धन्यवाद धन्यवाद धन्यवाद! मैंने सेल को टॉगल-सक्षम बनाने के लिए थोड़ा सा कोड जोड़ा। मैंने नीचे कोड जोड़ा।
सेप्ट्रॉनिक

14

पुनः लोडडाटा अच्छा नहीं है क्योंकि कोई एनीमेशन नहीं है ...

यह मैं वर्तमान में कोशिश कर रहा हूँ:

NSArray* paths = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]];
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView deleteRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];

यह लगभग सही काम करता है। लगभग। मैं सेल की ऊँचाई बढ़ा रहा हूं, और कभी-कभी तालिका दृश्य में थोड़ी "हिचकी" होती है जैसे सेल को प्रतिस्थापित किया जाता है, जैसे कि टेबल व्यू में कुछ स्क्रॉलिंग स्थिति संरक्षित की जा रही है, नई सेल (जो पहली सेल है तालिका में) इसकी भरपाई बहुत अधिक होती है, और स्क्रॉलव्यू इसे पुन: प्रस्तुत करने के लिए बाउंस करता है।


व्यक्तिगत रूप से मैंने पाया कि इस विधि का उपयोग करके लेकिन UITableViewRowAnimationNone के साथ एक चिकनी प्रदान करता है, लेकिन फिर भी सही परिणाम नहीं मिलता है।
रॉन सेरब्रॉन

11

मुझे नहीं पता कि उत्तराधिकार में शुरुआत / अंत में कॉल करने के बारे में यह सब क्या है, आप बस उपयोग कर सकते हैं -[UITableView reloadRowsAtIndexPaths:withAnimation:]यहाँ एक उदाहरण परियोजना है


बहुत बढ़िया यह मेरे ऑटो लेआउट सेल में मेरे पाठ विचारों को नहीं बढ़ाता है। लेकिन इसमें एनीमेशन के लिए एक झिलमिलाहट होना चाहिए क्योंकि सेल आकार को अपडेट करते समय कोई भी एनीमेशन विकल्प गड़बड़ नहीं दिखता है।
h3dkandi

10

मैंने साथ हल किया reloadRowsAtIndexPaths

मैं didSelectRowAtIndexPathचयनित सेल के indexPath में सहेजता हूं और reloadRowsAtIndexPathsअंत में कॉल करता हूं (आप तत्व की सूची के लिए NSMutableArray भेज सकते हैं जिसे आप पुनः लोड करना चाहते हैं)।

यदि heightForRowAtIndexPathआप इंडेक्सपाथ सूची में हैं या नहीं, तो आप जांच कर सकते हैं कि क्या IndexexPath सेल का और ऊंचाई भेजना है।

आप इस मूल उदाहरण की जाँच कर सकते हैं: https://github.com/ferminhg/iOS-Examples/tree/master/iOS-UITableView-Cell-Height-Change/celdascambiadetam यह एक सरल उपाय है।

यदि आप मदद करते हैं तो मैं एक तरह का कोड जोड़ता हूं

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 20;
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath: (NSIndexPath*)indexPath
{
    if ([indexPath isEqual:_expandIndexPath])
        return 80;

    return 40;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Celda";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    [cell.textLabel setText:@"wopwop"];

    return cell;
}

#pragma mark -
#pragma mark Tableview Delegate Methods

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSMutableArray *modifiedRows = [NSMutableArray array];
    // Deselect cell
    [tableView deselectRowAtIndexPath:indexPath animated:TRUE];
    _expandIndexPath = indexPath;
    [modifiedRows addObject:indexPath];

    // This will animate updating the row sizes
    [tableView reloadRowsAtIndexPaths:modifiedRows withRowAnimation:UITableViewRowAnimationAutomatic];
}

8

beginUpdates()/ के बजाय endUpdates(), अनुशंसित कॉल अब है:

tableView.performBatchUpdates(nil, completion: nil)

Apple का कहना है, startUpdates / endUpdates के बारे में: "जब भी संभव हो, इस के बजाय performBatchUpdates (_: पूर्णता :) विधि का उपयोग करें।"

देखें: https://developer.apple.com/documentation/uikit/uitableview/1614908-beginupdates


3

यह कोशिश करें कि अनुक्रमणिका पंक्ति का विस्तार किया जाए:

@property (nonatomic) NSIndexPath *expandIndexPath;
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath
{
if ([indexPath isEqual:self.expandedIndexPath])
    return 100;

return 44;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSMutableArray *modifiedRows = [NSMutableArray array];
if ([indexPath isEqual:self.expandIndexPath]) {
    [modifiedRows addObject:self.expandIndexPath];
    self.expandIndexPath = nil;
} else {
    if (self.expandedIndexPath)
        [modifiedRows addObject:self.expandIndexPath];

    self.expandIndexPath = indexPath;
    [modifiedRows addObject:indexPath];
}

// This will animate updating the row sizes
[tableView reloadRowsAtIndexPaths:modifiedRows withRowAnimation:UITableViewRowAnimationAutomatic];

// Preserve the deselection animation (if desired)
[tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ViewControllerCellReuseIdentifier];
    cell.textLabel.text = [NSString stringWithFormat:@"I'm cell %ld:%ld", (long)indexPath.section, (long)indexPath.row];

return cell;
}

3
BOOL flag;

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    flag = !flag;
    [tableView beginUpdates];
    [tableView reloadRowsAtIndexPaths:@[indexPath] 
                     withRowAnimation:UITableViewRowAnimationAutomatic];
    [tableView endUpdates];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return YES == flag ? 20 : 40;
}

2

कस्टम सेल पर "अधिक विवरण" जोड़ने के लिए मेरे जैसे किसी व्यक्ति के लिए बस एक नोट।

[tableView beginUpdates];
[tableView endUpdates];

एक उत्कृष्ट काम किया, लेकिन "फसल" सेल दृश्य को मत भूलना। इंटरफ़ेस बिल्डर से अपने सेल का चयन करें -> कंटेंट व्यू -> प्रॉपर्टी इंस्पेक्टर से " क्लिप सबव्यू " चुनें


2

हेम्स स्विफ्ट 3 के लिए सिमंस के उत्तर का एक छोटा संस्करण है। सेल के चयन के लिए भी अनुमति देता है

var cellIsSelected: IndexPath?


  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    cellIsSelected = cellIsSelected == indexPath ? nil : indexPath
    tableView.beginUpdates()
    tableView.endUpdates()
  }


  func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if cellIsSelected == indexPath {
      return 250
    }
    return 65
  }

2

स्विफ्ट 4 और उससे अधिक

नीचे दिए गए कोड को आप टेबलव्यू की डिडक्ट पंक्ति प्रतिनिधि विधि में जोड़ें

tableView.beginUpdates()
tableView.setNeedsLayout()
tableView.endUpdates()

1

साइमन ली के जवाब का स्विफ्ट संस्करण।

// MARK: - Variables 
  var isCcBccSelected = false // To toggle Bcc.



    // MARK: UITableViewDelegate
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {

    // Hide the Bcc Text Field , until CC gets focused in didSelectRowAtIndexPath()
    if self.cellTypes[indexPath.row] == CellType.Bcc {
        if (isCcBccSelected) {
            return 44
        } else {
            return 0
        }
    }

    return 44.0
}

फिर didSelectRowAtIndexPath () में

  func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    self.tableView.deselectRowAtIndexPath(indexPath, animated: true)

    // To Get the Focus of CC, so that we can expand Bcc
    if self.cellTypes[indexPath.row] == CellType.Cc {

        if let cell = tableView.cellForRowAtIndexPath(indexPath) as? RecipientTableViewCell {

            if cell.tag == 1 {
                cell.recipientTypeLabel.text = "Cc:"
                cell.recipientTextField.userInteractionEnabled = true
                cell.recipientTextField.becomeFirstResponder()

                isCcBccSelected = true

                tableView.beginUpdates()
                tableView.endUpdates()
            }
        }
    }
}

1

हाँ, यह मुमकिन है।

UITableView एक प्रतिनिधि विधि है didSelectRowAtIndexPath

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [UIView animateWithDuration:.6
                          delay:0
         usingSpringWithDamping:UIViewAnimationOptionBeginFromCurrentState
          initialSpringVelocity:0
                        options:UIViewAnimationOptionBeginFromCurrentState animations:^{

                            cellindex = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section];
                            NSArray* indexArray = [NSArray arrayWithObjects:indexPath, nil];
                            [violatedTableView beginUpdates];
                            [violatedTableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationAutomatic];
                            [violatedTableView endUpdates];
                        }
                     completion:^(BOOL finished) {
    }];
}

लेकिन आपके मामले में यदि उपयोगकर्ता स्क्रॉल करता है और एक अलग सेल का चयन करता है तो u को वर्तमान में चयनित सेल reloadRowsAtIndexPaths:कॉल्स को heightForRowAtIndexPath:उसी हिसाब से सिकोड़ने और विस्तारित करने के लिए अंतिम चयनित सेल की आवश्यकता होती है ।


0

यहाँ मेरा कस्टम UITableViewउपवर्ग का कोड है , जो UITextViewबिना पुनः लोड किए (और खोए हुए कीबोर्ड फ़ोकस) के बिना, तालिका सेल में विस्तृत होता है :

- (void)textViewDidChange:(UITextView *)textView {
    CGFloat textHeight = [textView sizeThatFits:CGSizeMake(self.width, MAXFLOAT)].height;
    // Check, if text height changed
    if (self.previousTextHeight != textHeight && self.previousTextHeight > 0) {
        [self beginUpdates];

        // Calculate difference in height
        CGFloat difference = textHeight - self.previousTextHeight;

        // Update currently editing cell's height
        CGRect editingCellFrame = self.editingCell.frame;
        editingCellFrame.size.height += difference;
        self.editingCell.frame = editingCellFrame;

        // Update UITableView contentSize
        self.contentSize = CGSizeMake(self.contentSize.width, self.contentSize.height + difference);

        // Scroll to bottom if cell is at the end of the table
        if (self.editingNoteInEndOfTable) {
            self.contentOffset = CGPointMake(self.contentOffset.x, self.contentOffset.y + difference);
        } else {
            // Update all next to editing cells
            NSInteger editingCellIndex = [self.visibleCells indexOfObject:self.editingCell];
            for (NSInteger i = editingCellIndex; i < self.visibleCells.count; i++) {
                UITableViewCell *cell = self.visibleCells[i];
                CGRect cellFrame = cell.frame;
                cellFrame.origin.y += difference;
                cell.frame = cellFrame;
            }
        }
        [self endUpdates];
    }
    self.previousTextHeight = textHeight;
}

0

मैंने @ जॉय के भयानक उत्तर का उपयोग किया, और इसने ios 8.4 और XCode 7.1.1 के साथ पूरी तरह से काम किया।

यदि आप अपने सेल को टॉगल-सक्षम बनाने के लिए देख रहे हैं, तो मैंने -tableViewDidSelect को निम्न में बदल दिया है:

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
//This is the bit I changed, so that if tapped once on the cell, 
//cell is expanded. If tapped again on the same cell, 
//cell is collapsed. 
    if (self.currentSelection==indexPath.row) {
        self.currentSelection = -1;
    }else{
        self.currentSelection = indexPath.row;
    }
        // animate
        [tableView beginUpdates];
        [tableView endUpdates];

}

मुझे उम्मीद है कि इसमें से किसी ने आपकी मदद की।


0

IOS 7 और बाद में इस विधि की जाँच करें।

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return UITableViewAutomaticDimension;
}

IOS 8 में इसमें सुधार किए गए हैं। हम इसे टेबल व्यू की संपत्ति के रूप में सेट कर सकते हैं।



0

इनपुट्स -

tableView.beginUpdates () tableView.endUpdates () ये फ़ंक्शन कॉल नहीं करेंगे

func tableView (_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {}

लेकिन, यदि आप करते हैं, tableView.reloadRows (at: [selectIndexPath! As IndexPath!, With: .none)

यह func tableView (_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {} इस फ़ंक्शन को कॉल करेगा ।


-1

मैंने बस थोड़ी सी हैक के साथ इस समस्या को हल किया है:

static int s_CellHeight = 30;
static int s_CellHeightEditing = 60;

- (void)onTimer {
    cellHeight++;
    [tableView reloadData];
    if (cellHeight < s_CellHeightEditing)
        heightAnimationTimer = [[NSTimer scheduledTimerWithTimeInterval:0.001 target:self selector:@selector(onTimer) userInfo:nil repeats:NO] retain];
}

- (CGFloat)tableView:(UITableView *)_tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
        if (isInEdit) {
            return cellHeight;
        }
        cellHeight = s_CellHeight;
        return s_CellHeight;
}

जब मुझे अपने द्वारा निर्धारित सेल ऊंचाई का विस्तार करने isInEdit = YESऔर विधि को कॉल करने की आवश्यकता होती है [self onTimer]और यह s_CellHeightEditing मान तक पहुंचने तक सेल की वृद्धि को एनिमेट करता है :-)


सिम्युलेटर में बहुत अच्छा काम करता है, लेकिन iPhone में हार्डवेयर खराब है। 0.05 टाइमर देरी और 5 इकाइयों की सेलहाइट वृद्धि के साथ, यह बहुत बेहतर है, लेकिन
CoreAnimation

1
पुष्टि करें, पोस्ट से पहले..एक समय।
अजय_नासा

-2

पंक्ति की अनुक्रमणिका का चयन करें। तालिका को पुनः लोड करें। UITableViewDelegate की ऊँचाई फ़ोरराउटअंडेक्सपैथ विधि में, एक अलग ऊँचाई के लिए चयनित पंक्ति की ऊँचाई सेट करें और दूसरों के लिए सामान्य पंक्ति ऊँचाई वापस करें


2
-1, काम नहीं करता है। [table reloadData]ऊंचाई में परिणाम कॉलिंग एनिमेशन के बजाय तुरन्त घटित होते हैं।
मार्क एमी जूल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.