2013-06-27 71 views
47

目前,我正在使用UITableView以及UIScrollView中包含的其他視圖。我希望UITableView的高度與其內容高度相同。UIScrollView中的UITableView使用自動佈局

使事情變得複雜,我還插入/刪除行以提供手風琴效果,以便當用戶點擊一行時,它將顯示該行的更多詳細信息。

我已經得到了插入/刪除完成,但目前它不更新的UIScrollView這是它的父使得UIScrollView的內容大小被重新計算並與在UIScrollView其他視圖是沿着UITableView正確顯示。

如何才能實現這個功能,以便在更改UITableView的內容時調整UIScrollView的尺寸並正確佈置其內容?我目前正在使用自動佈局。

+0

您添加的UITableView在UIScrollView中????? – iPatel

+0

是的,UITableView不佔用整個可見區域。我很清楚UITableView有一個UIScrollView。要禁用滾動,我將tableView的高度設置爲contentSize。 –

+2

UITableView本身有一個滾動視圖。那麼爲什麼要添加到另一個scrollView? – Meera

回答

83

首先,那些其他視圖(表視圖的同胞)是嚴格在表視圖的上方和下方嗎?如果是這樣,你是否考慮讓表視圖正常滾動,並將這些外部視圖放在表視圖的頁眉和頁腳視圖中?那麼你不需要滾動視圖。

其次,如果您尚未閱讀,您可能需要閱讀Technical Note TN2154: UIScrollView And Autolayout。第三,考慮到該技術說明中的信息,我可以想出幾種方法來做你想做的事。最乾淨的可能是創建一個實現intrinsicContentSize方法的UITableView的子類。實現是微不足道的:

@implementation MyTableView 

- (CGSize)intrinsicContentSize { 
    [self layoutIfNeeded]; // force my contentSize to be updated immediately 
    return CGSizeMake(UIViewNoIntrinsicMetric, self.contentSize.height); 
} 

@end 

然後,讓自動佈局使用表視圖的內在內容大小。在滾動視圖的子視圖(包括表格視圖)之間創建約束以將其展開,並確保滾動視圖的所有四個邊都有約束。

你可能需要發送invalidateIntrinsicContentSize以在適當的時間表格視圖(當您添加或刪除行或更改行的高度)。你可能只需重寫MyTableView中的適當方法即可。例如。做[self invalidateIntrinsicContentSize]-endUpdates-reloadData- insertRowsAtIndexPaths:withRowAnimation:

這裏是我的測試結果:

table view with intrinsic content size in scroll view

滾動視圖有淡藍色背景。紅頂標籤和藍底標籤是滾動視圖內的表視圖的兄弟。

這是我測試中視圖控制器的完整源代碼。沒有xib文件。

#import "ViewController.h" 
#import "MyTableView.h" 

@interface ViewController() <UITableViewDataSource, UITableViewDelegate> 

@end 

@implementation ViewController 

- (void)loadView { 
    UIView *view = [[UIView alloc] init]; 
    self.view = view; 

    UIScrollView *scrollView = [[UIScrollView alloc] init]; 
    scrollView.translatesAutoresizingMaskIntoConstraints = NO; 
    scrollView.backgroundColor = [UIColor cyanColor]; 
    [view addSubview:scrollView]; 

    UILabel *topLabel = [[UILabel alloc] init]; 
    topLabel.translatesAutoresizingMaskIntoConstraints = NO; 
    topLabel.text = @"Top Label"; 
    topLabel.backgroundColor = [UIColor redColor]; 
    [scrollView addSubview:topLabel]; 

    UILabel *bottomLabel = [[UILabel alloc] init]; 
    bottomLabel.translatesAutoresizingMaskIntoConstraints = NO; 
    bottomLabel.text = @"Bottom Label"; 
    bottomLabel.backgroundColor = [UIColor blueColor]; 
    [scrollView addSubview:bottomLabel]; 

    UITableView *tableView = [[MyTableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain]; 
    tableView.translatesAutoresizingMaskIntoConstraints = NO; 
    tableView.dataSource = self; 
    tableView.delegate = self; 
    [scrollView addSubview:tableView]; 

    UILabel *footer = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 30)]; 
    footer.backgroundColor = [UIColor greenColor]; 
    footer.text = @"Footer"; 
    tableView.tableFooterView = footer; 

    NSDictionary *views = NSDictionaryOfVariableBindings(
     scrollView, topLabel, bottomLabel, tableView); 
    [view addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"V:|[scrollView]|" 
     options:0 metrics:nil views:views]]; 
    [view addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"H:|[scrollView]|" 
     options:0 metrics:nil views:views]]; 
    [view addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"V:|[topLabel][tableView][bottomLabel]|" 
     options:0 metrics:nil views:views]]; 
    [view addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"H:|[topLabel]|" 
     options:0 metrics:nil views:views]]; 
    [view addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"H:|-8-[tableView]-8-|" 
     options:0 metrics:nil views:views]]; 
    [view addConstraint:[NSLayoutConstraint 
     constraintWithItem:tableView attribute:NSLayoutAttributeWidth 
     relatedBy:NSLayoutRelationEqual 
     toItem:view attribute:NSLayoutAttributeWidth 
     multiplier:1 constant:-16]]; 
    [view addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"H:|[bottomLabel]|" 
     options:0 metrics:nil views:views]]; 
} 

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; 
    if (!cell) { 
     cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; 
    } 
    cell.textLabel.text = [NSString stringWithFormat:@"Row %d", indexPath.row]; 
    return cell; 
} 

@end 
+5

**重要提示:**需要使用桌腳才能使用! (失去了一小時 - ') – AncAinu

+4

感謝您的這個偉大的答案!節省了我的時間!我所做的子類的要點(它的工作原理沒有頁眉和頁腳,太):https://gist.github.com/booiiing/7941890 –

+1

這工作得很好,除了內容的大小,動畫的變化在哪裏tableViews的大小隻會在tableView裏面的動畫完成後纔會改變 – Ahti

44

除了搶劫的答案有UITableView的自調整大小的子類的SWIFT例如:

斯威夫特2.x的

class IntrinsicTableView: UITableView { 

    override var contentSize:CGSize { 
     didSet { 
      self.invalidateIntrinsicContentSize() 
     } 
    } 


    override func intrinsicContentSize() -> CGSize { 
     self.layoutIfNeeded() 
     return CGSizeMake(UIViewNoIntrinsicMetric, contentSize.height) 
    } 

} 

斯威夫特3.X斯威夫特4。X

class IntrinsicTableView: UITableView { 

    override var contentSize:CGSize { 
     didSet { 
      self.invalidateIntrinsicContentSize() 
     } 
    } 

    override var intrinsicContentSize: CGSize { 
     self.layoutIfNeeded() 
     return CGSize(width: UIViewNoIntrinsicMetric, height: contentSize.height) 
    } 

} 

我已經用它把一個表視圖到另一個自動調整大小的表視圖的單元格。

+0

我試着寫在迅速3 重寫此方法FUNC intrinsicContentSize() 而是顯示的錯誤 - >方法不覆蓋任何超類 –

+6

斯威夫特3已經取代了有利於功能:覆蓋VAR intrinsicContentSize:CGSize –

8

這裏是OBJ-C版本。它是基於從用戶@MuHAOS解決

@implementation SizedTableView 

- (void)setContentSize:(CGSize)contentSize { 
    [super setContentSize:contentSize]; 
    [self invalidateIntrinsicContentSize]; 
} 

- (CGSize)intrinsicContentSize { 
    [self layoutIfNeeded]; // force my contentSize to be updated immediately 
    return CGSizeMake(UIViewNoIntrinsicMetric, self.contentSize.height); 
} 


@end 
+0

我們如何能夠用故事板 –

+1

使其@AmrAngry讓你的tableview類是SizedTableView –

+0

這應該被標記爲完美答案。 – Nil

1

@ MuHAOS的和@ klemen-zagar代碼幫了我很多,但通過在tableview中包含一個堆棧視圖中引發無限的佈局循環實際上導致性能問題,它本身包含在滾動視圖中。請參閱下面的解決方案

@interface AutoSizingTableView() 
@property (nonatomic, assign) BOOL needsIntrinsicContentSizeUpdate; 
@end 

@implementation AutoSizingTableView 

- (void)setContentSize:(CGSize)contentSize 
{ 
    [super setContentSize:contentSize]; 

    self.needsIntrinsicContentSizeUpdate = YES; 
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
     if (!self.needsIntrinsicContentSizeUpdate) { 
      return; 
     } 

     self.needsIntrinsicContentSizeUpdate = NO; 
     [self layoutIfNeeded]; 
     [self invalidateIntrinsicContentSize]; 
    }); 
} 

- (CGSize)intrinsicContentSize 
{ 
    return CGSizeMake(UIViewNoIntrinsicMetric, self.contentSize.height); 
} 

@end 
0

您可以將視圖添加爲tableview的headerview和footerview。因爲tableview是scrollview的子視圖。 按照下面的例子。

UILabel *topLabel = [[UILabel alloc] init]; 
topLabel.translatesAutoresizingMaskIntoConstraints = NO; 
topLabel.text = @"Top Label"; 
topLabel.backgroundColor = [UIColor redColor]; 
tableView.tableFooterView = topLabel; 

UILabel *footer = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 30)]; 
    footer.backgroundColor = [UIColor greenColor]; 
    footer.text = @"Footer"; 
    tableView.tableFooterView = footer; 

,你也可以添加headerview和使用簡單的拖放的tableview的footerview和故事板視圖拖放到的tableview和利用這一看法IBOutlet中。

相關問題