【问题标题】:How to resize a tableHeaderView of a UITableView?如何调整 UITableView 的 tableHeaderView 的大小?
【发布时间】:2010-09-25 08:53:33
【问题描述】:

我在调整 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 的大小???

有人能做到吗?

谢谢

iMe

【问题讨论】:

    标签: iphone cocoa-touch uitableview


    【解决方案1】:

    仅供参考:我已经通过修改 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];
    

    【讨论】:

    • +1 这对我有用。在您的子视图更改大小后调用“setTableHeaderView”是关键。问题是,我的子视图会在一秒钟内改变大小作为动画。现在我想弄清楚如何用它为 tableHeaderView 设置动画。
    • 完美,非常感谢。对我来说,这是 Objective-C 中不太理想的属性之一的示例。我们无法知道(我们也没有理由知道)设置标题会产生重新计算高度的副作用。它应该在我们更新标题的高度时自动执行,或者我们应该每次都调用类似[tableView recalculateHeaderHeight] 的东西。
    • @Andrew 我知道这几乎是迟到了一年,但迟到总比永远好:我能够通过用 [tableview beginUpdates] 包装 setTableHeaderView: 调用来为表头视图的变化高度设置动画和[tableview endUpdates]
    • @jasongregori 您添加的方便评论 - 我看到相同的技术(beginUpdates+endUpdates)不会像 tableHeaderView 那样为 tableFooterView 的高度变化设置动画。您是否也找到了为 tableFooterView 设置动画的好方法?
    • 令人印象深刻,它在 UIView 动画块中执行它时会起作用,尽管我认为在这种情况下它不是很有效。
    【解决方案2】:

    这个答案很旧,显然不适用于 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,则滚动将像标题视图没有调整大小一样进行动画处理(如果动画是快)。

    【讨论】:

    • 完美运行,删除了动画,因为我不需要它。
    • 在 iOS7 发生之前完美运行...在下面添加了我的解决方案
    • WTF?你把 UITableView 的内部搞得一团糟,你真的不应该对它在较新的 iOS 版本中不起作用感到惊讶...... ;)
    【解决方案3】:

    如果您想有条件地为更改设置动画,您可以执行以下操作:

    - (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 下方单元格的动画。这是使用beginUpdatesendUpdates 完成的
    2. 实际标题视图的动画。这是使用UIView 动画块完成的。

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

    更新

    我在 gihub 上创建了一个 Xcode 项目,它就是这样做的。 查看besi/ios-quickies中的项目ResizeTableHeaderViewAnimated

    【讨论】:

    • 此技术确实有效,但不适用于带有节标题的表格视图。当您使用开始更新/结束更新时,它会干扰动画块,留下重复的部分标题。
    【解决方案4】:

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

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

    【讨论】:

    • 这确实有效,但前提是在 viewDidLayoutSubviews 中使用
    • 这在 tableView.reloadData 之前调用时有效。
    【解决方案5】:

    在 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];
    }
    

    【讨论】:

      【解决方案6】:

      这在 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];
      }];
      

      【讨论】:

        【解决方案7】:

        因为tableHeaderView的setter。

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

        【讨论】:

          【解决方案8】:

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

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

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

          【讨论】:

            【解决方案9】:

            在 iOS 9.x 上,在 viewDidLoad 上执行此操作就可以了:

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

            headerView 被声明为@IBOutlet var headerView: UIView! 并连接到故事板上,它被放置在 tableView 的顶部,用作 tableHeaderView。

            【讨论】:

              【解决方案10】:

              这仅适用于您使用自动布局并将translatesAutoresizingMaskIntoConstraints = false 设置为自定义标题视图时。

              最好和最简单的方法是覆盖intrinsicContentSize。在内部 UITableView 使用 intrinsicContentSize 来决定其页眉/页脚大小。在自定义视图中覆盖 intrinsicContentSize 后,您需要做的如下

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

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

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

              【讨论】:

                【解决方案11】:

                对于 swift 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/

                【讨论】:

                  【解决方案12】:

                  viewDidLoad 中为标题视图属性tableView.tableHeaderView 设置高度 似乎不起作用,标题视图高度仍然没有按预期更改。

                  在多次尝试解决这个问题之后。我发现,您可以通过调用标题视图创建逻辑来更改高度 - (void)didMoveToParentViewController:(UIViewController *)parent 方法。

                  所以示例代码如下所示:

                  - (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];
                      }
                  }
                  

                  【讨论】:

                    【解决方案13】:

                    如果自定义 headerView 是使用自动布局设计的,并且 headerView 需要在 web-fetch 或类似的惰性任务之后更新。 然后在 iOS-Swift 中我这样做并使用以下代码更新了我的 headerView:

                    //to reload your cell data
                    self.tableView.reloadData()
                    DispatchQueue.main.async {
                    // 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()
                    }
                    

                    【讨论】:

                      【解决方案14】:

                      我发现 UIView 的 initWithFrame 初始化程序没有正确地支持我传入的 rect。因此,我做了以下完美的工作:

                       - (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 获取框架是个坏主意,你将如何重用你的视图?
                      【解决方案15】:

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

                      // 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
                      }
                      

                      【讨论】:

                        【解决方案16】:

                        UITableView 调整标题 - UISearchBar with Scope Bar

                        我想要一个 UITableView 和一个 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;
                        }
                        

                        【讨论】:

                          【解决方案17】:

                          显然,现在 Apple 应该已经为 tableHeaderView 和 tableFooterView 实现了 UITableViewAutomaticDimension...

                          使用布局约束,以下似乎对我有用:

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

                          【讨论】:

                            【解决方案18】:

                            如果你的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上测试过,运行良好。

                            【讨论】:

                              【解决方案19】:

                              你试过了吗 [self.tableView reloadData]改变高度后?

                              【讨论】:

                              • 是关于tableHeaderView,它是一个静态视图。 - [UITableView reloadData] 仅适用于动态视图(单元格)以及您显然认为的 sectionHeaders ;)
                              猜你喜欢
                              • 1970-01-01
                              • 1970-01-01
                              • 2012-07-24
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              相关资源
                              最近更新 更多