UITableView tableFooterView 显示在 UITableView 的顶部 - 错误

Posted

技术标签:

【中文标题】UITableView tableFooterView 显示在 UITableView 的顶部 - 错误【英文标题】:UITableView tableFooterView shows at the top of the UITableView - wrong 【发布时间】:2017-09-25 17:59:03 【问题描述】:

我创建了一个非常简单的测试用例来重现这个问题。

我正在尝试以编程方式将页脚视图设置为表格视图。请注意,我指的是 tableview 最底部的页脚 - 而不是节页脚(大多数堆栈溢出答案使他们感到困惑)。

这是我非常简单的代码:

- (void)viewDidLoad 
    [super viewDidLoad];
    UIView *footerContainer = [[UIView alloc] initWithFrame:CGRectZero];
    footerContainer.backgroundColor=[UIColor greenColor];
    footerContainer.translatesAutoresizingMaskIntoConstraints=NO;
    [footerContainer addConstraints:@[[NSLayoutConstraint
                                       constraintWithItem:footerContainer attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual
                                       toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:100
                                       ],
                                      [NSLayoutConstraint
                                       constraintWithItem:footerContainer attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual
                                       toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:[UIScreen mainScreen].bounds.size.width
                                       ]]];

    self.mytableview.tableFooterView=footerContainer;
    [self.view setNeedsLayout];
    [self.view layoutIfNeeded];


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    return 10;


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    cell.textLabel.text=[NSString stringWithFormat:@"%ld",indexPath.row];
    return cell;

然而,结果是这样的:

如您所见,页脚显示在 tableview 的顶部。这是一个错误还是我错过了什么?

如果我将 tableFooterView 更改为 tableHeaderView,那么它工作正常。所以我期望同样的方法也适用于页脚,但事实并非如此。

【问题讨论】:

设置 translatesAutoresizingMaskIntoConstraints = NO 可能会破坏 tableview 用于定位页脚的任何方法。 您是否使用约束是因为您将(或可能)在页脚视图中有动态内容?如果是这样,我可以给你一个解决方案... @DonMag 是的,我正在寻找一种解决方案,该解决方案将使用约束来设置它,而不是手动设置框架。我的实际应用具有动态大小的页脚内容。 【参考方案1】:

不要在分配给tableView.tableFooterViewUIView 上设置translatesAutoresizingMaskIntoConstraints = false

在您的情况下,这是footerContainer。我有同样的问题。在对该问题的评论中提到了这一点,但在我注意到我正在这样做之前,我仍然花了几个小时进行故障排除,所以我也把它放在这里作为可能的答案。

【讨论】:

第二个。 这么多这个!【参考方案2】:

动态大小的UITableView 页眉和页脚视图并不总是能很好地配合自动布局,所以你需要给它一点帮助。

这是一个示例,它为页脚视图创建了一个简单的UIView,并添加了一个“扩展”UILabel(行数设置为零)。页脚视图是为其框架使用显式 CGRect 创建的,并且标签通过自动布局约束固定到所有四个边。

viewDidLayoutSubviews() 中,我们告诉自动布局根据其内容的约束条件计算页脚视图的框架,然后我们更新框架值(嗯,特别是高度)。

//
// this assumes IBOutlet has been set for "theTableView"
//

- (void)viewDidLoad 
    [super viewDidLoad];

    // standard stuff
    [_theTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"simpleCell"];
    _theTableView.delegate = self;
    _theTableView.dataSource = self;

    // instantiate a view for the table footer
    // width doesn't matter (it will be stretched to fit the table by default)
    // set height to a big number to avoid a "will attempt to break constraint" warning
    UIView *footerContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1, 1000)];

    // give it a color so we can see it
    footerContainer.backgroundColor=[UIColor greenColor];

    // set the footer view
    _theTableView.tableFooterView = footerContainer;


    // instantiate a label to add to the footer view
    UILabel *aLabel = [UILabel new];

    // auto-sizing the height, so set lines to zero
    aLabel.numberOfLines = 0;

    // give it a color so we can see it
    aLabel.backgroundColor = [UIColor yellowColor];

    // set the text to 8 lines for demonstration purposes
    aLabel.text = @"Line 1\nLine 2\nLine 3\nLine 4\nLine 5\nLine 6\nLine 7\nLine 8";

    // standard, for auto-sizing
    aLabel.translatesAutoresizingMaskIntoConstraints = NO;

    // add the label to the footer view
    [footerContainer addSubview:aLabel];

    // constraint the label to 8-pts from each edge...
    [aLabel.topAnchor constraintEqualToAnchor:footerContainer.topAnchor constant:8.0].active = YES;
    [aLabel.leftAnchor constraintEqualToAnchor:footerContainer.leftAnchor constant:8.0].active = YES;
    [aLabel.rightAnchor constraintEqualToAnchor:footerContainer.rightAnchor constant:-8.0].active = YES;
    [aLabel.bottomAnchor constraintEqualToAnchor:footerContainer.bottomAnchor constant:-8.0].active = YES;



- (void)viewDidLayoutSubviews 
    [super viewDidLayoutSubviews];

    // get a reference to the table's footer view
    UIView *currentFooterView = [_theTableView tableFooterView];

    // if it's a valid reference (the table *does* have a footer view)
    if (currentFooterView) 

        // tell auto-layout to calculate the size based on the footer view's content
        CGFloat newHeight = [currentFooterView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

        // get the current frame of the footer view
        CGRect currentFrame = currentFooterView.frame;

        // we only want to do this when necessary (otherwise we risk infinite recursion)
        // so... if the calculated height is not the same as the current height
        if (newHeight != currentFrame.size.height) 
            // use the new (calculated) height
            currentFrame.size.height = newHeight;
            currentFooterView.frame = currentFrame;
        

    


这在尝试使自动调整大小的表格视图标题视图正常工作时也很有帮助。

【讨论】:

【参考方案3】:

我已经在 swift 中对显式帧值进行了同样的尝试,并且我实现了您所要求的行为,如果您认为它没问题,请尝试使用显式帧值。如果不需要,则删除布局约束。

   @IBOutlet weak var tableView: UITableView!

override func viewDidLoad() 
    super.viewDidLoad()

    tableView.delegate = self
    tableView.dataSource = self

    let footerView = UIView(frame: CGRect.init(x: 0, y: 0, width: tableView.frame.width, height: 50))
    footerView.backgroundColor = UIColor.green
    tableView.tableFooterView = footerView


extension ViewController: UITableViewDelegate, UITableViewDataSource 

func numberOfSections(in tableView: UITableView) -> Int 
    return 1


func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return 10


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
    cell?.textLabel?.text = "\(indexPath.row)"
    return cell!

【讨论】:

这对我有用,是的。这是否意味着自动布局与页脚视图有问题?我应该将其记录为 Apple 的错误吗? @PranoyC :很高兴它解决了您的问题,抱歉,我没有使用手动自动布局代码的风格,无法帮助您直接回答您的错误报告想法,但我建议如果您要提出问题,请在尝试在视图控制器中为简单视图设置自动布局后提出。 这个问题可以通过容器视图来解决。请参阅下面的答案。 您的回答帮助了我,让我朝着正确的方向前进。我只使用老朋友自动调整大小的蒙版来修复它,第二次我什至对我的标签施加了约束,混乱释放了。毫无疑问,这是一个 Apple 漏洞。 试试更小的设备,你会看到它的样子。错了。【参考方案4】:

您可以使用AutolayoutXibs 创建页脚视图。但是您必须将自定义视图放到容器视图中,然后分配给 tableFooterView

func setupTableFooterView() 
    // Create your footer view from XIB and set constraints (in my case it is historyToolBarView of class HistoryToolBarView)
    let view = Bundle.main.loadNibNamed("HistoryToolBarView", owner: self, options: nil)?.first
    historyToolBarView = view as! HistoryToolBarView
    historyToolBarView.translatesAutoresizingMaskIntoConstraints = false
    historyToolBarView.addConstraints(
        [NSLayoutConstraint.init(item: self.historyToolBarView,
                                 attribute: .height,
                                 relatedBy: .equal,
                                 toItem: nil,
                                 attribute: .notAnAttribute,
                                 multiplier: 1.0,
                                 constant: 60),
         NSLayoutConstraint.init(item: self.historyToolBarView,
                                 attribute: .width,
                                 relatedBy: .equal,
                                 toItem: nil,
                                 attribute: .notAnAttribute,
                                 multiplier: 1.0,
                                 constant: UIScreen.main.bounds.size.width)])

    // Create a container of your footer view called footerView and set it as a tableFooterView
    let footerView = UIView(frame: CGRect.init(x: 0, y: 0, width: tableView.frame.width, height: 60))
    footerView.backgroundColor = UIColor.green
    tableView.tableFooterView = footerView

    // Add your footer view to the container
    footerView.addSubview(historyToolBarView)

【讨论】:

【参考方案5】:

表格视图忽略了约束。 手动设置height 即可:

tableView.tableFooterView?.frame.size.height = 20

【讨论】:

【参考方案6】:

为表格设置分组样式并为标题设置高度 CGFloat.leastNonzeroMagnitude

tableView.style = .grouped

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat 
    return CGFloat.leastNonzeroMagnitude

【讨论】:

以上是关于UITableView tableFooterView 显示在 UITableView 的顶部 - 错误的主要内容,如果未能解决你的问题,请参考以下文章

将 UITableView 推送到 UITableView

UItableview 单元格的动态高度与 UItableview 单元格内的 UItableview

UITableView

水平 UITableView 中的垂直 UITableView

如何与重叠显示的 UITableView 交互另一个 UITableView

在 UITableView 中的 UINib 中重新加载 UITableView