2010-11-28 39 views
1

嘗試我最先在這裏找到答案,但我卡住了。我有一個UITableView設置與UITableViewStyleGrouped 4節,每個有一個或兩個行。在其中兩個部分中,我需要一排更大的高度來容納我粘在那裏的內容。不同高度的分組UITableView行導致內容洗牌

看起來不錯,除非我上下滾動時,textLablels,配件和額外的子視圖開始轉變成不同的行列,我不知道爲什麼。

這個screenshot顯示加載時的表格視圖,然後在我上下滾動幾次後顯示。每當我滾動不同的行內容時,

我以爲我讀了一些關於這是分組風格的問題。果然,如果我將表格樣式更改爲默認值,我不會看到此問題。使用分組樣式時,我不允許動態設置某些行的高度嗎?

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    if (indexPath.section == kSection_Info && indexPath.row == kSectionRow_InfoPhoto) 
    { 
     return 84.0; 
    } 
    else if (indexPath.section == kSection_Level && indexPath.row == kSectionRow_LevelLevel) 
    { 
     return 70.0; 
    } 
    return 44.0; 
} 

我在celForRowAtIndexPath手動設置每一行:

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

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (cell == nil) 
    { 
     cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 

     switch (indexPath.section) 
     { 
      case kSection_Info: 
      { 
       switch (indexPath.row) 
       { 
        case kSectionRow_InfoName: 
        { 
         cell.textLabel.text = @"Name"; 
         cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 
         self.nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(74, 8, 195, 25)]; 
         self.nameLabel.textAlignment = UITextAlignmentRight; 
         self.nameLabel.font = [UIFont systemFontOfSize:16]; 
         self.nameLabel.textColor = [UIColor blueColor]; 
         self.nameLabel.text = self.currentRecipient.fullName;      
         [cell.contentView addSubview:self.nameLabel]; 

         break; 
        } 
        case kSectionRow_InfoPhoto: 
        { 
         cell.textLabel.text = @"Photo"; 
         self.imageButton = [UIButton buttonWithType:UIButtonTypeCustom]; 
         self.imageButton.frame = CGRectMake(10, 14, 64, 64); 
         [self.imageButton addTarget:self action:@selector(onImageButtonTouch:) forControlEvents:UIControlEventTouchUpInside];     

         NSString *imageName = @"add_image.png"; 
         UIImage *thumb = [UIImage imageNamed:imageName]; 
         [self.imageButton setImage:thumb forState:UIControlStateNormal]; 
         cell.accessoryView = self.imageButton; 

         break; 
        } 
        default: 
        { 
         break; 
        } 
       } 
       break; 
      } 

      case kSection_List: 
      { 
       switch (indexPath.row) 
       { 
        case kSectionRow_ListHasList: 
        { 
         cell.textLabel.text = @"Is Listed";     
         self.listSwitch = [[UISwitch alloc] initWithFrame:CGRectZero]; 
         cell.accessoryView = self.listSwitch;     

         break; 
        } 
        case kSectionRow_ListBudget: 
        { 
         cell.textLabel.text = @"List Amount"; 
         cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 
         self.budgetLabel = [[UILabel alloc] initWithFrame:CGRectMake(124, 8, 145, 25)]; 
         self.budgetLabel.textAlignment = UITextAlignmentRight; 
         self.budgetLabel.font = [UIFont systemFontOfSize:16]; 
         self.budgetLabel.textColor = [UIColor blueColor]; 
         self.budgetLabel.text = [@"$" stringByAppendingFormat:@"%0.2f", [self.currentRecipient.budget floatValue]];      
         [cell.contentView addSubview:self.budgetLabel]; 

         break; 
        } 
        default: 
        { 
         break; 
        } 
       } 
       break; 
      } 

      case kSection_Level: 
      { 
       switch (indexPath.row) 
       {    
        case kSectionRow_LevelLevel: 
        { 
         self.levelSlider = [[UISlider alloc] initWithFrame:CGRectMake(8, 2, 284, 40)]; 
         self.levelSlider.minimumValue = 0.0; 
         self.levelSlider.maximumValue = 100.0; 
         self.levelSlider.continuous = YES; 

         UIImage *meterImage = [UIImage imageNamed:@"meter_labels.png"]; 
         UIImageView *meterView = [[UIImageView alloc] initWithFrame:CGRectMake(8, 32, 284, 24)]; 
         [meterView setImage:meterImage]; 

         [cell.contentView addSubview:self.levelSlider]; 
         [cell.contentView addSubview:meterView]; 
         [meterImage release]; 

         break; 
        } 
        case kSectionRow_LevelHasLevel: 
        { 
         cell.textLabel.text = @"Show Level"; 
         self.levelSwitch = [[[UISwitch alloc] initWithFrame:CGRectZero] autorelease]; 
         cell.accessoryView = self.levelSwitch;        
         break; 
        }      
        default: 
        { 
         break; 
        } 
       } 
       break; 
      } 

      case kSection_RecipientDelete: 
      { 
       cell.textLabel.text = @"Delete Recipient";   
       cell.textLabel.textAlignment = UITextAlignmentCenter; 
       cell.textLabel.textColor = [UIColor blueColor];    
       break; 
      } 

      default: 
      { 
       break; 
      } 
     } 
    } 

    return cell; 
} 
+0

你的`tableView:cellForRowAtIndexPath:`方法是什麼樣的? – 2010-11-28 20:35:59

+0

添加到我的問題,謝謝! – bread 2010-11-28 21:46:47

回答

0

「內容洗牌」你看到的是最有可能因處理細胞再利用的不當。

對分組風格沒有特別的問題。問題更可能以這種風格表現出來,因爲更少的單元適合屏幕,這需要更多的滾動並需要更多的單元重用。

您只在創建單元格時設置單元格內容(當單元格爲nil時)。當一個單元格從屏幕上滾動時,它會進入重用隊列。現在可見的另一端的行重新使用了重用隊列中的單元視圖。重用的單元格包含其他行的內容。

當所有的單元格相似(至少關於UI控件而不是數據)時,這不是問題。當所有或部分單元格不同時,控件會出現在您不期望的地方。


因爲你只有一小行數和每一個不同奠定了,快(也許是髒的)解決方案是使用一個不同的再利用標識符這樣每個單元:

NSString *CellIdentifier = 
    [NSString stringWithFormat:@"RecipientEntryCell-%d-%d", 
    indexPath.section, indexPath.row]; 

如果表格視圖將有許多不同的單元格,則不建議使用這種方法,因爲表格中每行的每個單元格將同時存儲在內存中(而不僅僅是屏幕上的少數幾個單元格)。 不要使用唯一標識符來解決任何和所有單元重用問題。

Table View Programming Guide展示了一種設計表格視圖的替代方法,就像這樣,您有幾個單元格具有不同的佈局。請參閱this page上的「靜態行內容技術」。


最終,如果您明白表格視圖重用單元格的原因很好,並且不會一直試圖解決該問題,那麼最好。一般情況下,的cellForRowAtIndexPath應該是這樣的:

static NSString *CellIdentifier = @"CellIdentifier"; 

UITableViewCell *cell = [tableView dequeueReusableCell... 
if (cell == nil) { 
    //Create cell... 
    //Set UI content that applies to all rows (if any)... 
} 
else { 
    //Cell is being re-used. 
    //Remove UI content that doesn't apply to this row... 
} 

//Add UI content that applies only to this row... 

//Copy values from data source to cell UI controls... 

return cell; 

如果您構建細胞如上圖所示,不維持細胞內到UI控件類級別引用(如nameLabel,ImageButton的,等等)。相反,控制值應該在來自後備數據變量(模型)的cellForRowAtIndexPath中進行設置,並且只要UI控件更改,應該讀取該值或將其保存回後備數據變量。

例如,不是在單元格中存儲對UISlider的引用,而是將當前滑塊值存儲爲浮點型ivar。在適當的地方初始化float(例如viewDidLoad)。在cellForRowAtIndexPath中,創建UISlider,使用float伊娃設置它的值,並在滑塊的值改變時讓滑塊調用一個方法。在該方法中,將滑塊的值複製到浮點伊娃。

希望這會有所幫助。