ios tableFooterView 属性不修复表视图底部的页脚

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15687370/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 22:55:43  来源:igfitidea点击:

tableFooterView property doesn't fix the footer at the bottom of the table view

iosuitableview

提问by Malloc

I am setting a footer view in the viewDidLoad method:

我在 viewDidLoad 方法中设置页脚视图:

UIView *fView = [[UIView alloc] initWithFrame:CGRectMake(0, 718, 239, 50)];
fView.backgroundColor =[UIColor yellowColor];
self.table.tableFooterView = fView;

Unfortunately, the footer is not drawing in the specified (x,y)specified above, but it stick with the cells, so if the table view has 4 cells, the footer will be drawn in the 5th cell.

不幸的是,页脚没有在(x,y)上面指定的指定中绘制,但它与单元格保持一致,因此如果表视图有 4 个单元格,则页脚将在第 5 个单元格中绘制。

I even tried the protocol method, tableView:viewForFooterInSection

我什至尝试了协议方法, tableView:viewForFooterInSection

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{

UIView *fView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 239, 50)];
fView.backgroundColor =[UIColor yellowColor];
    return fView;
}

the problem is not resolved, I am sure tableFooterViewproperty should fi the footer view at the bottom of the table view but I am not sure what I may be missing here? Thanx in advance.

问题没有解决,我确定tableFooterView属性应该在表视图底部的页脚视图中显示,但我不确定我在这里可能遗漏了什么?提前谢谢。

回答by rmaddy

Since your goal is to have a footer that stays fixed at the bottom of the screen, and not scroll with the table, then you can't use a table view footer. In fact, you can't even use a UITableViewController.

由于您的目标是让页脚固定在屏幕底部,而不是随表格滚动,因此您不能使用表格视图页脚。事实上,你甚至不能使用UITableViewController.

You must implement your view controller as a UIViewController. Then you add your own table view as a subview. You also add your footer as a subview of the view controller's view, not the table view. Make sure you size the table view so its bottom is at the top of the footer view.

您必须将视图控制器实现为UIViewController. 然后将自己的表视图添加为子视图。您还将页脚添加为视图控制器视图的子视图,而不是表视图。确保调整表格视图的大小,使其底部位于页脚视图的顶部。

You will need to make your view controller conform to the UITableViewDataSourceand UITableViewDelegateprotocols and hook everything up to replicate the functionality of UITableViewController.

您需要使您的视图控制器符合UITableViewDataSourceUITableViewDelegate协议并将所有内容连接起来以复制UITableViewController.

回答by Martin Ullrich

A footer view will always be added to the bottom of content.
This means that a section footer will be added below the cells of a section, a table footer view to the bottom of all sections - regardless of the position you set in your view.

页脚视图将始终添加到内容的底部。
这意味着节页脚将添加到节的单元格下方,表格页脚视图添加到所有节的底部 - 无论您在视图中设置的位置如何。

If you want to add a "static" content, you should consider adding a view outside of the table view (superview) - which isn't possible if you use UITableViewController- or you use [self.table addSubView:view]and adjust the position/transform to the table view's contentOffsetproperty in the scrollViewDidScroll:delegate method (UITableViewis a subclass of UIScrollViewso you also get it's delegate calls) like in this code:

如果你想添加一个“静态”内容,你应该考虑在表视图(超级视图)之外添加一个视图 - 如果你使用这是不可能的UITableViewController- 或者你使用[self.table addSubView:view]并调整位置/转换到表视图的contentOffset属性该scrollViewDidScroll:委托方法(UITableView是的子类UIScrollView,所以你还可以得到它的委托电话)像这样的代码:

@implementation YourTableViewController {
    __weak UIView *_staticView;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    UIView *staticView = [[UIView alloc] initWithFrame:CGRectMake(0, self.tableView.bounds.size.height-50, self.tableView.bounds.size.width, 50)];
    staticView.backgroundColor = [UIColor redColor];
    [self.tableView addSubview:staticView];
    _staticView = staticView;
    self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 50, 0);
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    _staticView.transform = CGAffineTransformMakeTranslation(0, scrollView.contentOffset.y);
}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    // this is needed to prevent cells from being displayed above our static view
    [self.tableView bringSubviewToFront:_staticView];
}

...

回答by cohen72

Another way is to use UITableViewControllerin a storyboard, and embed it within a UIViewController as a container view. Then you can use auto layout to set the relationship between the footer and the container view which contains the UITableView

另一种方法是UITableViewController在故事板中使用,并将其作为容器视图嵌入到 UIViewController 中。然后您可以使用自动布局来设置页脚和包含以下内容的容器视图之间的关系UITableView

回答by Steve Moser

If your table view or table view controller is wrapped by a navigation controller consider using the navigation controller's UIToolbar. It will always stick to the bottom.

如果您的表视图或表视图控制器由导航控制器包装,请考虑使用导航控制器的 UIToolbar。它会一直粘在底部。

[self.navigationController setToolbarHidden:NO];

回答by JordanC

I was able to get a label to be fixed to the bottom of my static UITableViewController. Not the perfect solution for all scenarios, but worked for my simple needs.

我能够将标签固定到我的静态 UITableViewController 的底部。不是适用于所有场景的完美解决方案,但可以满足我的简单需求。

UIView* v = [[UIView alloc] initWithFrame:self.view.bounds];
CGFloat labelHeight = 30;
CGFloat padding = 5;
UILabel* l = [[UILabel alloc] initWithFrame:CGRectMake(0, v.frame.size.height - labelHeight - padding, self.view.frame.size.width, labelHeight)];
l.text = @"Hello World";
[v addSubview:l];
[self.tableView setBackgroundView:v];

回答by KaQu

It looks like something similar to below works quite well:

看起来类似于下面的东西效果很好:

import PlaygroundSupport
import UIKit

let testVC = UITableViewController(style: .grouped)
testVC.view.frame = CGRect(x: 0, y: 0, width: 400, height: 700)
testVC.view.backgroundColor = .white

class TableViewDataSourceDelegate : NSObject {
    var rows = 2
}

extension TableViewDataSourceDelegate : UITableViewDataSource, UITableViewDelegate {

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

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return rows
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
        cell.backgroundColor = .red
        return cell
    }

    func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {

        let tableViewHeight = tableView.bounds.size.height
        let varticalMargin: CGFloat
        if #available(iOS 11.0, *) {
            varticalMargin = tableView.directionalLayoutMargins.bottom + tableView.directionalLayoutMargins.top
        } else {
            varticalMargin = tableView.layoutMargins.bottom + tableView.layoutMargins.top
        }

        let verticalInset: CGFloat
        if #available(iOS 11.0, *) {
            verticalInset = tableView.adjustedContentInset.bottom + tableView.adjustedContentInset.top
        } else {
            verticalInset = tableView.contentInset.bottom + tableView.contentInset.top
        }
        let tableViewContentHeight = tableView.contentSize.height - varticalMargin


        let height: CGFloat
        if #available(iOS 11.0, *) {
            let verticalSafeAreaInset = tableView.safeAreaInsets.bottom + tableView.safeAreaInsets.top
            height = tableViewHeight - tableViewContentHeight - verticalInset - verticalSafeAreaInset
        } else {
            height = tableViewHeight - tableViewContentHeight - verticalInset
        }

        if (height < 0) {
            return 0
        } else {
            return height
        }
    }

    func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
        let extraButtonSpace = UIView()
        extraButtonSpace.backgroundColor = .clear
        return extraButtonSpace
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if indexPath.row == 0 {
            tableView.beginUpdates()
            rows += 1
            tableView.insertRows(at: [indexPath], with: .automatic)
            tableView.endUpdates()
        } else if indexPath.row == 1 {
            tableView.beginUpdates()
            rows -= 1
            tableView.deleteRows(at: [indexPath], with: .automatic)
            tableView.endUpdates()
        } else {
            tableView.beginUpdates()
            tableView.endUpdates()
        }
    }
}


let controller = TableViewDataSourceDelegate()
testVC.tableView.delegate = controller
testVC.tableView.dataSource = controller
testVC.tableView.reloadData()

let extraButtonSpace = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 80))
extraButtonSpace.backgroundColor = .yellow
testVC.tableView.tableFooterView = extraButtonSpace

PlaygroundPage.current.liveView = testVC.view

Screen from playground

操场的屏幕

回答by NoN

If you want to make footer fixed at bottom, you should create custom footerView and change footer frame when tableView content size is changing:

如果您想让页脚固定在底部,您应该创建自定义页脚视图并在 tableView 内容大小更改时更改页脚框架:

-(void)changeCustomTableFooterYPositionWithTableFrame:(CGRect)tableFrame tableContentSize: (CGSize) tableContentSize {
    CGFloat originalTableViewTopEdgeInset = self.tableView.contentInset.top;
    CGFloat originalTableViewBottomEdgeInset = self.tableView.contentInset.bottom - self.tableFooterView.frame.size.height;

    CGFloat footerViewYPositionByContentSize = tableContentSize.height;
    CGFloat footerViewYPositionByTableSize = tableFrame.size.height - self.tableFooterView.frame.size.height - originalTableViewTopEdgeInset - originalTableViewBottomEdgeInset;
    CGFloat tableFooterViewYPosition = MAX(footerViewYPositionByContentSize, footerViewYPositionByTableSize);

    self.tableFooterView.frame = CGRectMake(self.tableFooterView.frame.origin.x, tableFooterViewYPosition, self.customTableFooterView.frame.size.width, self.customTableFooterView.frame.size.height);
}

To detect when contentSize was changed add observer to contentSize:

要检测 contentSize 何时更改,将观察者添加到 contentSize:

 [self addObserver: self forKeyPath: @"tableView.contentSize" options: NSKeyValueObservingOptionNew + NSKeyValueObservingOptionOld context: ContentSizeContext];

Do not forget to change tableView.edgeInsets when insert footer:

插入页脚时不要忘记更改 tableView.edgeInsets:

self.tableView.contentInset = UIEdgeInsetsMake(self.tableView.contentInset.top, self.tableView.contentInset.left, self.tableView.contentInset.bottom + self.customTableFooterView.frame.size.height, self.tableView.contentInset.right);

You can see inherited class and example at the link below: TableViewWithFooterAtBottom

您可以在下面的链接中看到继承的类和示例: TableViewWithFooterAtBottom

回答by Lucas Chwe

The following is the solution for this footer problem, when we do NOT want the footer to stick in the bottom all the time, AKA. it only sticks to the bottom when there are not enough rows to fill the screen, or when the user scrolls all the way down of the screen.

以下是这个页脚问题的解决方案,当我们不希望页脚一直粘在底部时,AKA。当没有足够的行来填充屏幕时,或者当用户一直向下滚动屏幕时,它只会粘在底部。

Add your self.footerViewto your self.tableViewas a subview on -viewDidLoad:or somewhere like that, then set the delegate for self.tableView, update the content inset of the tableview to self.tableView.contentInset = UIEdgeInsetsMake(0, 0, CGRectGetHeight(self.footerView), 0);and set up the following methods:

将您self.footerViewself.tableView作为子视图添加到您的子视图中-viewDidLoad:或类似的地方,然后为 设置委托self.tableView,将 tableview 的内容插入更新为self.tableView.contentInset = UIEdgeInsetsMake(0, 0, CGRectGetHeight(self.footerView), 0);并设置以下方法:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
  [self updateFooterView];
}

- (void)updateFooterView
{
  CGRect sectionFrame = [self.tableView rectForSection:0];
  CGFloat bottomSpace = self.tableView.contentOffset.y + CGRectGetHeight(self.tableView.frame) - CGRectGetMaxY(sectionFrame);
  CGFloat footerHeight = CGRectGetHeight(self.footerView.frame);
  CGFloat transformY = self.tableView.contentOffset.y + footerHeight - MIN(bottomSpace,footerHeight);

  CGRect footerFrame = self.footerView.frame;
  footerFrame.origin.y = self.tableView.bounds.size.height - footerFrame.size.height + transformY;
  self.footerView.frame = footerFrame;
}

Whenever you need to update the footer (i.e. after adding a new row), just call -updateFooterViewand you should be good

每当你需要更新页脚(即添加新一行之后),只需调用-updateFooterView,你应该是好的

回答by Alex Zanfir

You can use this to make the table look smaller according to how many rows do you have :

您可以使用它根据您有多少行来使表格看起来更小:

    let tblView =  UIView(frame: CGRectZero)
    tableView.tableFooterView = tblView
    tableView.tableFooterView!.hidden = true
    tableView.backgroundColor = UIColor.clearColor()

Another alternative would be to just change the height for row at index path depending on for what number minimum rows you have that problem.

另一种选择是根据您遇到该问题的最小行数更改索引路径中行的高度。

回答by Romulo Diniz

Im not super proud of this solution, but it worked for me using only IB as of today. It will use the toolbar area of your UITableViewController, if that works for you.

我对这个解决方案并不感到非常自豪,但它对我来说只有今天使用 IB 才有效。它将使用您的 UITableViewController 的工具栏区域,如果它适合您的话。

  1. Create a new temporary UIViewController
  2. Drag a Toolbar into this UIViewController
  3. Drag a UIView on this toolbar. I used the elements tree on the left for that, was easier. This will create a BarButtonItem you'll move on step 5.
  4. Drag a BarButtonItem on your UITableViewController, this will create a Toolbar items section.
  5. Drag the BarButtonItem created on step 3 into the Toolbar items section created on step 4.
  6. Delete the UIViewController and edit the BarButtonItem as you wish.
  1. 创建一个新的临时 UIViewController
  2. 将一个 Toolbar 拖入这个 UIViewController
  3. 在此工具栏上拖动一个 UIView。为此,我使用了左侧的元素树,更容易。这将创建一个 BarButtonItem,您将在第 5 步中继续操作。
  4. 在 UITableViewController 上拖动一个 BarButtonItem,这将创建一个 Toolbar items 部分。
  5. 将在步骤 3 中创建的 BarButtonItem 拖到在步骤 4 中创建的工具栏项部分。
  6. 删除 UIViewController 并根据需要编辑 BarButtonItem。