如何调整UITableView的tableHeaderView的大小?


103

我无法调整tableHeaderView的大小。简单行不通。

1)创建一个UITableView和UIView(100 x 320 px);

2)设置UIView为UITableView的tableHeaderView;

3)构建并运行。一切都好。

现在,我想调整tableHeaderView的大小,因此我将以下代码添加到viewDidLoad中:

self.tableView.autoresizesSubviews = YES;

self.tableView.tableHeaderView = myHeaderView;
self.tableView.tableFooterView = myFooterView;

CGRect newFrame = self.tableView.tableHeaderView.frame;
newFrame.size.height = newFrame.size.height + 100;
self.tableView.tableHeaderView.frame = newFrame;

tableHeaderView的高度应显示为200,但应显示为100。

如果我写:

self.tableView.autoresizesSubviews = YES;


CGRect newFrame = myHeaderView.frame;
newFrame.size.height = newFrame.size.height + 100;
myHeaderView.frame = newFrame;


self.tableView.tableHeaderView = myHeaderView;
self.tableView.tableFooterView = myFooterView;

然后,根据我的需要,它以200的高度开始。但我希望能够在运行时对其进行修改。

我也尝试过,但没有成功:

self.tableView.autoresizesSubviews = YES;

self.tableView.tableHeaderView = myHeaderView;
self.tableView.tableFooterView = myFooterView;

CGRect newFrame = self.tableView.tableHeaderView.frame;
newFrame.size.height = newFrame.size.height + 100;
self.tableView.tableHeaderView.frame = newFrame;

[self.tableView.tableHeaderView setNeedsLayout];
[self.tableView.tableHeaderView setNeedsDisplay];
[self.tableView setNeedsLayout];
[self.tableView setNeedsDisplay];

这里的重点是:我们如何在运行时调整tableHeaderView的大小?

有谁能做到这一点?

谢谢

Answers:


180

仅供参考:我已经通过修改tableHeaderView并重新设置来使其工作。在这种情况下,当UIWebView子视图完成加载时,我正在调整tableHeaderView的大小。

[webView sizeToFit];
CGRect newFrame = headerView.frame;
newFrame.size.height = newFrame.size.height + webView.frame.size.height;
headerView.frame = newFrame;
[self.tableView setTableHeaderView:headerView];

13
+1这对我有用。子视图更改大小后,调用“ setTableHeaderView”是关键。问题是,我的子视图在一秒钟内将大小更改为动画。现在,我试图弄清楚如何用它对tableHeaderView进行动画处理。
安德鲁(Andrew)2010年

1
完美,谢谢。对我来说,这是Objective-C中较不理想的特性之一的示例。我们没有办法知道(也没有理由应该知道)设置标头会带来重新计算高度的副作用。它应该在更新标头的高度时自动执行此操作,或者应该要求[tableView recalculateHeaderHeight]每次调用类似的内容。
jakeboxer 2010年

48
@Andrew我知道这将近一年了,但是迟到总比没有好:我能够通过将setTableHeaderView:调用包装为[tableview beginUpdates][tableview endUpdates]
jasongregori 11/11/15

2
您添加的@jasongregori方便注释-我看到相同的技术(beginUpdates + endUpdates)不能像它执行tableHeaderView那样为tableFooterView设置高度变化的动画。您是否还找到了动画tableFooterView的好方法?
克里斯(Kris)

1
令人印象深刻的是,它在UIView动画块中运行时起作用,尽管我认为这种情况下效率不高。
可以

12

这个答案是旧的,显然不适用于iOS 7及更高版本。

我遇到了同样的问题,并且我还想让更改动起来,所以我为标题视图制作了UIView的子类,并添加了以下方法:

- (void)adjustTableHeaderHeight:(NSUInteger)newHeight{
    NSUInteger oldHeight = self.frame.size.height;
    NSInteger originChange = oldHeight - newHeight;

    [UIView beginAnimations:nil context:nil];

    [UIView setAnimationDuration:1.0f];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];

    self.frame = CGRectMake(self.frame.origin.x, 
                        self.frame.origin.y, 
                        self.frame.size.width, 
                        newHeight);

    for (UIView *view in [(UITableView *)self.superview subviews]) {
        if ([view isKindOfClass:[self class]]) {
            continue;
        }
        view.frame = CGRectMake(view.frame.origin.x, 
                            view.frame.origin.y - originChange, 
                            view.frame.size.width, 
                            view.frame.size.height);
    }

    [UIView commitAnimations];
}

- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context{
    [(UITableView *)self.superview setTableHeaderView:self];
}

本质上,这使UITableView的所有子视图与调用类的类类型都不相同。动画结束时,它将在超级视图(UITableView)上调用setTableHeaderView -如果不这样做,则UITableView内容将在用户下次滚动时跳回。到目前为止,我发现的唯一限制是,如果用户尝试在动画进行时滚动UITableView,则滚动将进行动画处理,就好像没有调整标题视图的大小(如果动画是快)。


效果很好,删除了动画,因为我不需要它。
Jiho Kang 2012年

完美运行直到iOS7出现...在下面添加了我的解决方案
avishic 2013年

1
WTF?您对UITableView的内部一无所知,以至于它在新的iOS版本中不起作用时,您真的不应该感到惊讶……;)
Daniel Rinser 2014年

10

如果要有条件地对更改进行动画处理,则可以执行以下操作:

- (void) showHeader:(BOOL)show animated:(BOOL)animated{

    CGRect closedFrame = CGRectMake(0, 0, self.view.frame.size.width, 0);
    CGRect newFrame = show?self.initialFrame:closedFrame;

    if(animated){
        // The UIView animation block handles the animation of our header view
        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:0.3];
        [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];

        // beginUpdates and endUpdates trigger the animation of our cells
        [self.tableView beginUpdates];
    }

    self.headerView.frame = newFrame;
    [self.tableView setTableHeaderView:self.headerView];

    if(animated){
        [self.tableView endUpdates];
        [UIView commitAnimations];
    }
}

请注意,动画是双重的:

  1. 下方的单元格的动画tableHeaderView。这是使用beginUpdates和完成的endUpdates
  2. 实际标题视图的动画。这是使用UIView动画块完成的。

为了同步这两个动画,animationCurve必须将设置为UIViewAnimationCurveEaseInOut,将持续时间设置为0.3,这似乎是UITableView用于其动画的方式。

更新资料

我在gihub上创建了一个Xcode项目。ResizeTableHeaderViewAnimatedbesi / ios-quickies检出项目

屏幕截图


2
此技术有效,但不适用于带有节标题的表视图。使用开始更新/结束更新时,它会干扰动画块,并留下重复的节标题。
BlueFish

9

我认为如果您像这样设置myHeaderView的高度,它应该可以工作:

CGRect newFrame = myHeaderView.frame;
newFrame.size.height = newFrame.size.height + 100;
myHeaderView.frame = newFrame;

self.tableView.tableHeaderView = myHeaderView;

这实际上有效,但仅当在viewDidLayoutSubviews中使用时
KoCMoHaBTa 2014年

6

直到iOS 7为止,都
在上面使用@garrettmoon解决方案。这是基于@garrettmoon的更新解决方案:

- (void)adjustTableHeaderHeight:(NSUInteger)newHeight animated:(BOOL)animated {

    [UIView beginAnimations:nil context:nil];

    [UIView setAnimationDuration:[CATransaction animationDuration]];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];

    self.frame = CGRectMake(self.frame.origin.x,
                        self.frame.origin.y,
                        self.frame.size.width,
                        newHeight);

    [(UITableView *)self.superview setTableHeaderView:self];

    [UIView commitAnimations];
}

- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context{
    [(UITableView *)self.superview setTableHeaderView:self];
}

5

这在iOS 7和8上对我有用。此代码在表视图控制器上运行。

[UIView animateWithDuration:0.3 animations:^{
    CGRect oldFrame = self.headerView.frame;
    self.headerView.frame = CGRectMake(oldFrame.origin.x, oldFrame.origin.y, oldFrame.size.width, newHeight);
    [self.tableView setTableHeaderView:self.headerView];
}];

4

这是因为tableHeaderView的设置器。

在设置tableHeaderView之前,必须先设置UIView的高度。(如果Apple开源此框架,会容易得多...)


4

在iOS 9及更低版本上,tableHeaderView调整大小后将不会重新布局。此问题已在iOS 10中解决。

要解决此问题,只需使用以下代码即可:

self.tableView.tableHeaderView = self.tableView.tableHeaderView;

2

在iOS 9.x上,viewDidLoad可以正常运行:

var frame = headerView.frame
frame.size.height = 11  // New size
headerView.frame = frame

headerView声明为@IBOutlet var headerView: UIView!并连接在情节提要上,并放置在tableView的顶部,以用作tableHeaderView。


2

仅在使用自动布局并设置translatesAutoresizingMaskIntoConstraints = false为自定义标题视图时才适用。

最好和最简单的方法是覆盖intrinsicContentSize。内部UITableView用于intrinsicContentSize确定其页眉/页脚大小。intrinsicContentSize在自定义视图中覆盖后,您需要执行的操作如下

  1. 配置自定义页眉/页脚视图的布局(子视图)
  2. 调用 invalidateIntrinsicContentSize()
  3. 调用tableView.setNeedsLayout()tableView.layoutIfNeeded()

然后,UITableView的页眉/页脚将根据需要进行更新。无需将视图设置为nil或重置。

对于UITableView.tableHeaderViewor而言.tableFooterView,真正有趣的一件事是UIStackView失去了管理它的能力arrangedSubviews。如果要UIStackView用作tableHeaderView或tableFooterView,则必须将stackView嵌入到中,UIView并覆盖UIViewintrinsicContentSize


2

快速的5个测试代码

override func viewDidLayoutSubviews() {
      super.viewDidLayoutSubviews()

        guard let headerView = self.tblProfile.tableHeaderView else {
            return
        }

        let size = headerView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)

        if headerView.frame.size.height != size.height {
            headerView.frame.size.height = size.height
            self.tblProfile.tableHeaderView = headerView
            self.tblProfile.layoutIfNeeded()
        }
    }

注意:您需要从上,下,前,尾给出所有子视图的约束。因此,它将获得整个所需的大小。

参考来自: https : //useyourloaf.com/blog/variable-height-table-view-header/


1

设置高度为标题视图属性tableView.tableHeaderViewviewDidLoad似乎没有工作,预计头视图高度仍不会改变。

针对这个问题进行了许多尝试之后。我发现,可以通过在- (void)didMoveToParentViewController:(UIViewController *)parent方法内部调用标题视图create逻辑来更改高度 。

因此,示例代码如下所示:

- (void)didMoveToParentViewController:(UIViewController *)parent {
    [super didMoveToParentViewController:parent];

    if ( _tableView.tableHeaderView == nil ) {
        UIView *header = [[[UINib nibWithNibName:@"your header view" bundle:nil] instantiateWithOwner:self options:nil] firstObject];

        header.frame = CGRectMake(0, 0, CGRectGetWidth([UIScreen mainScreen].bounds), HeaderViewHeight);

        [_tableView setTableHeaderView:header];
    }
}

0

我发现UIView的initWithFrame初始值设定项不能正确地兑现我所传入的矩形。因此,我做了以下工作,它们效果很好:

 - (id)initWithFrame:(CGRect)aRect {

    CGRect frame = [[UIScreen mainScreen] applicationFrame];

    if ((self = [super initWithFrame:CGRectZero])) {

        // Ugly initialization behavior - initWithFrame will not properly honor the frame we pass
        self.frame = CGRectMake(0, 0, frame.size.width, 200);

        // ...
    }
}

这样做的好处是可以更好地封装到您的视图代码中。


从中获取框架UIScreen不是一个好主意,您将如何重用视图?
Zorayr

0

我实现了表格标题的动画高度更改,以在点击时扩展到整个屏幕。但是,该代码可以在其他情况下提供帮助:

// Swift
@IBAction func tapped(sender: UITapGestureRecognizer) {

    self.tableView.beginUpdates()       // Required to update cells. 

    // Collapse table header to original height
    if isHeaderExpandedToFullScreen {   

        UIView.animateWithDuration(0.5, animations: { () -> Void in
            self.scrollView.frame.size.height = 110   // original height in my case is 110
        })

    }
    // Expand table header to overall screen            
    else {      
        let screenSize = self.view.frame           // "screen" size

        UIView.animateWithDuration(0.5, animations: { () -> Void in
            self.scrollView.frame.size.height = screenSize.height
        })
    }

    self.tableView.endUpdates()  // Required to update cells. 

    isHeaderExpandedToFullScreen= !isHeaderExpandedToFullScreen  // Toggle
}

0

UITableView调整大小标头-具有范围栏的UISearchBar

我想要一个UITableView以a UISearchBar作为表头,所以我有一个看起来像这样的层次结构

UITableView
  |
  |--> UIView
  |     |--> UISearchBar
  |
  |--> UITableViewCells

UISearchBarDelegate方法

如其他地方所述,如果更改后未设置setTableViewHeader,则不会发生任何事情。

- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
    searchBar.showsScopeBar = YES;
    [UIView animateWithDuration:0.2f animations:^{
        [searchBar sizeToFit];
        CGFloat height = CGRectGetHeight(searchBar.frame);

        CGRect frame = self.tableView.tableHeaderView.frame;
        frame.size.height = height;
        self.tableHeaderView.frame = frame;
        self.tableView.tableHeaderView = self.tableHeaderView;
    }];

    [searchBar setShowsCancelButton:YES animated:YES];
    return YES;
}

- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar
{
    searchBar.showsScopeBar = NO;
    [UIView animateWithDuration:0.f animations:^{
        [searchBar sizeToFit];

        CGFloat height = CGRectGetHeight(searchBar.frame);

        CGRect frame = self.tableView.tableHeaderView.frame;
        frame.size.height = height;
        self.tableHeaderView.frame = frame;
        self.tableView.tableHeaderView = self.tableHeaderView;
    }];

    [searchBar setShowsCancelButton:NO animated:YES];
    return YES;
}

0

如果自定义headerView是使用自动布局设计的,则在Web提取或类似的延迟任务之后需要更新headerView。然后在iOS-Swift中,我这样做了,并使用下面的代码更新了headerView:

//to reload your cell data
self.tableView.reloadData()
dispatch_async(dispatch_get_main_queue(),{
// this is needed to update a specific tableview's headerview layout on main queue otherwise it's won't update perfectly cause reloaddata() is called
  self.tableView.beginUpdates()
  self.tableView.endUpdates()
} 

0

显然,到目前为止,Apple应该已经为tableHeaderView和tableFooterView实现了UITableViewAutomaticDimension ...

以下内容似乎适用于使用布局约束的我:

CGSize   s  = [ self  systemLayoutSizeFittingSize : UILayoutFittingCompressedSize ];
CGRect   f  = [ self  frame ];

f.size   = s;

[ self  setFrame : f ];

0

如果tableHeaderView是内容可调的webView,则可以尝试:

[self.webView.scrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    self.webView.height = self.webView.scrollView.contentSize.height;
    self.tableView.tableHeaderView = self.webView;
}

我在iOS9和iOS11上进行了测试,效果很好。


-3

[self.tableView reloadData]改变高度后您尝试 了吗?


1
关于tableHeaderView,这是一个静态视图。- [UITableView reloadData]仅用于动态视图(单元格)以及您显然认为是故意的sectionHeader;)
朱利安·F·
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.