iOS 8 - 最初从视图中隐藏 UITableView 的 headerView

iOS 8 - Initially hide a UITableView's headerView from view

就像在本机 iOS 邮件应用程序中一样,当我将 UITableViewController 推到 UINavigationController 上时,我想让 UITableView 最初看起来略微向下滚动,从而掩盖其 header在导航控制器的导航栏下方查看。

同时,即使所有单元格的高度都小于 table 视图的高度,用户也应该可以上下滚动以明确显示或隐藏header 再次查看。

从这个逻辑来看,对于这个实现似乎有两个考虑因素:

1) 确保 table 视图的最小内容大小至少为 table 视图框架的高度 + header 视图的高度。

2) 当 table 视图最初呈现时,内容偏移量增加 header 视图的高度。

我尝试手动设置 'viewWillAppear' 中 table 视图的 contentOffset 和 contentSize 属性,但这似乎没有效果(table 视图可能是在那之后重新加载)。尝试在 'viewDidAppear' 中设置它们会起作用,但为时已晚,因为只有在 'push' 动画完成后才会调用它。

虽然以前的 iOS 版本已经问过此类问题,但我无法让它们中的任何一个在 iOS 8 中工作。此外,它们都涉及更改偏移量,但不是 table 视图的 contentSize。

有人在 iOS 7 and/or 8 之前遇到过这种行为吗?

更新 - (30/1/2015)

好的。昨晚这对我来说不太好,所以我又玩了一次,我找到了一个更好更干净的解决方案。

我发现 UITableViewControllertableView 属性 不是 readonly。因此,在 UITableView 子类中简单地管理 contentSize 属性 然后将该子类分配回 UITableViewController.

实际上更有意义
@implementation TOCustomTableView

- (void)setContentSize:(CGSize)contentSize
{
    CGFloat scrollInset = self.contentInset.top + self.contentInset.bottom;
    CGFloat height = (CGRectGetHeight(self.bounds) - scrollInset) + CGRectGetHeight(self.tableHeaderView.frame);
    contentSize.height = MAX(height, contentSize.height);
    [super setContentSize:contentSize];
}

@end

---

@implementation TOCustomTableViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.tableView = [[TOCustomTableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
}

@end

这样,table 视图的最小值 contentSize 始终明确设置为 table 视图的高度 + headerView 大小,从而实现零抖动的预期效果。 :)


原答案

trick14 为我指明了正确的方向。所以我最终得到了正确运行的代码。

- (void)resetTableViewInitialOffset
{
    CGPoint contentOffset = self.tableView.contentOffset;
    contentOffset.y = self.tableView.contentInset.top + CGRectGetHeight(self.headerView.frame);
    self.tableView.contentOffset = contentOffset;
}

- (void)resetTableViewContentSize
{
    CGSize contentSize = self.tableView.contentSize;
    CGFloat scrollInset = self.tableView.contentInset.top + self.tableView.contentInset.bottom;
    CGFloat height = (CGRectGetHeight(self.view.bounds) - scrollInset) + CGRectGetHeight(self.headerView.frame);
    contentSize.height = MAX(height, contentSize.height);
    self.tableView.contentSize = contentSize;
}

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];

    if (!self.headerBarInitiallyHidden) {
        [self resetTableViewContentSize];
        [self resetTableViewInitialOffset];
        self.headerBarInitiallyHidden = YES;
    }
}

我还确保每次在 table 视图上执行 'reloadData' 时调用 'resetTableViewContentSize'。