2014-03-13 86 views
3

UITableViewUICollectionView中的單獨單元格的各部分與單獨的標題行對齊的慣用方法是什麼?iOS表格/集合視圖中的單元格間佈局邏輯

例如,假設我想這樣的東西顯示:

Name  Number 
Bob  34587 
Jane  32489 
Barbara 23766 
Montgomery 34892 

「名稱」和「號碼」位將是某種形式的標題單元格。我想我可以使用一節的標題爲此(與一節)。

標題下方的每個單元格都需要智能地確定其內容大小,但該大小需要影響所有其他單元格的佈局。

這通常是在iOS中實現的嗎?

+0

您是否希望這取決於名稱列中的內容(因此可變寬度),還是隻是將標題(「數字」)與數字對齊的情況? – Moonwalkr

回答

2

即使它被稱爲「表視圖」這是不是一個真正的表通常我們是怎樣想的表(,多列多行)。如果你真的想要多個列,這取決於你。要排列它們,你必須完成確定所需寬度的工作,或者選擇一個足夠大的寬度用於所有情況。

我想我會做這樣的事情:

#define COLUMN_SPACE 10 
- (UITableViewCell) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath { 
    MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: @"cell"]; 
    // Layout the cell 
    NSString *name = [myDataStore nameForIndexPath: indexPath]; 
    NSNumber *number = [myDataStore numberforIndexPath: indexPath]; 

    CGRect frame = cell.nameLabel.frame; 
    frame.size.width = [self nameColumnWidth]; 
    cell.nameLabel.frame = frame; 
    frame = cell.numberLabel.frame; 
    frame.origin.x = cell.nameLabel.origin.x + cell.nameLabel.size.width + COLUMN_SPACE; 
    frame.size.width = [self numberColumnWidth]; 
    cell.numberLabel.frame = frame; 

    cell.nameLabel.text = name; 
    // You would probably want to use an NSNumberFormatter here 
    cell.numberLabel.text = [NSString stringWithFormat: @"%d", number.intValue]; 

    return cell; 
} 

- (CGFloat) nameColumnWidth { 
    if(_nameColumnWidth <= 0.0) { 
     _nameColumnWidth = 0.0; 
     for(NSInteger s = 0; s < [myDataStore numberOfSections]; ++s) { 
      for(NSInteger r = 0; r < [myDataStore numberOfRowsInSection: s]; ++r) { 
       NSIndexPath *path = [NSIndexPath indexPathForRow: r inSection: s]; 
       NSString *name = [myDataStore nameForIndexPath: indexPath]; 
       CGFloat widthForName = [name widthNeeded]; 
       if(widthForName > _nameColumnWidth) 
        _nameColumnWidth = widthForName; 
      } 
     } 
    } 
    return _nameColumnWidth; 
} 

- (CGFloat) numberColumnWidth { 
    if(_numberColumnWidth <= 0.0) { 
     _numberColumnWidth = 0.0; 
     for(NSInteger s = 0; s < [myDataStore numberOfSections]; ++s) { 
      for(NSInteger r = 0; r < [myDataStore numberOfRowsInSection: s]; ++r) { 
       NSIndexPath *path = [NSIndexPath indexPathForRow: r inSection: s]; 
       NSNumber *number = [myDataStore numberforIndexPath: indexPath]; 
       // You would probably want to use an NSNumberFormatter here 
       // (in fact you want to do the same is you do in cellForRowAtIndexPath) 
       NSString *numberAsString = [NSString stringWithFormat: @"%d", number.intValue]; 
       CGFloat widthForNumber = [numberAsString widthNeeded]; 
       if(widthForNumber > _numberColumnWidth) 
        _numberColumnWidth = widthForNumber; 
      } 
     } 
    } 
    return _numberColumnWidth; 
} 

我會用同樣的[self nameColumnWidth][self numberColumnWidth]生成段標題視圖時,或者我只想讓細胞在部分的行0有名稱號碼標題。

對於寬度我將延伸NSString與此:

@implementation NSString (WithWidthNeeded) 
- (CGFloat) widthNeeded { 
    // Either set the font you will use here, add it as a parameter, etc. 
    UIFont *font = [UIFont systemFontOfSize: 18]; 
    CGSize maximumLabelSize = CGSizeMake(9999, font.lineHeight); 
    CGSize expectedLabelSize; 
    if([self respondsToSelector: @selector(boundingRectWithSize:options:attributes:context:)]) { 
     CGRect expectedLabelRect = [self boundingRectWithSize: maximumLabelSize options: NSStringDrawingUsesLineFragmentOrigin attributes: @{ NSFontAttributeName: font } context: nil]; 
      expectedLabelRect = CGRectIntegral(expectedLabelRect); 
      expectedLabelSize = expectedLabelRect.size; 
    } else { 
     NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString: self attributes: @{ NSFontAttributeName: font }]; 
     if([attributedText respondsToSelector: @selector(boundingRectWithSize:options:context:)]) { 
      CGRect expectedLabelRect = [attributedText boundingRectWithSize: maximumLabelSize options: NSStringDrawingUsesLineFragmentOrigin context: nil]; 
      expectedLabelRect = CGRectIntegral(expectedLabelRect); 
      expectedLabelSize = expectedLabelRect.size; 
    } else { 
      expectedLabelSize = [self sizeWithFont: font 
           constrainedToSize: maximumLabelSize 
            lineBreakMode: NSLineBreakByTruncatingTail]; 

     } 
    } 
    return expectedLabelSize.width; 
} 
@end 

當數據被改變_nameColumnWidth_numberColumnWidth可以更改爲0.0,它們將被重新計算,以便列寬將被調整。

另一種方法是保持名稱的最大寬度的軌道時的細胞cellForRowAtIndexPath被奠定了。如果它們增加,則觸發可見單元格重繪。這將有更好的性能,因爲它不必遍歷整個數據集以找到最長的名稱和最大的號碼。這,然而,導致列偏移,你通過數據滾動視圖下來,不再或更大遇到,除非最長和最大正好是最上面一行。

也可以做一種混合,其中nameColumnWidthnumberColumnWidth被設置爲最大可見(排序的局部最大值),但是後臺線程開始通過其餘數據並查找絕對最大值。當找到絕對最大值時,重新加載可見單元格。然後,列寬只有一個移位或變化。 (如果sizeWithFont:被調用,因爲它是在UIKit的後臺線程可能不是安全的。與iOS 6或7,我認爲這將是OK)

同樣,因爲UITableView真是UIColumnView它留下相當一點點的工作可以讓你製作多列,可以調整其內容的寬度。

2

如果我理解正確,那麼您希望第二列儘可能地靠近第一列,而不用制動第一列中的內容。

據我所知,這在iOS上不常用,因爲它對於兩列使用固定寬度的空間要容易得多,並且通常不需要水平壓縮它們。

但是,如果我真的要做到這一點,那麼:通過調用的NSString方法 sizeWithFont:contrainedToSize:

  1. 我想通過我的所有單元格的內容運行週期,並確定左內容的大小 (如果在iOS7之前使用或者在iOS7上使用 boundingRectWithSize:options:attributes:context:)。
  2. 我會存儲實例變量中的最大值(例如 _maxLeftContentWidth)。
  3. 在我的-tableView:cellForRowAtIndexPath:我會根據我存儲的 實例變量(_maxLeftContentWidth)爲我的 左側單元格內容和右側單元格內容設置框架。
  4. 每當內容爲我的單元格更改時,我會再次運行左側單元格寬度計算方法,然後調用[self.tableView reloadData]來重繪單元格。
相關問題