动态 UITableView 高度

Posted

技术标签:

【中文标题】动态 UITableView 高度【英文标题】:Dynamic UITableView height 【发布时间】:2015-12-23 06:00:54 【问题描述】:

我想设置 UITableView 以匹配表格视图中所有内容的高度。

这是我的故事板

这个问题是顶部和底部的 ImageView 在屏幕上总是静态的。

表格视图中假设有 10 个项目,但由于屏幕尺寸限制,仅显示 7 个。我想在用户能够看到底部的 ImageView 之前显示所有 10 个。 (顺便说一句,所有 3 个视图,即图像视图和表格视图都在 uiscrollview 中)

理想

我必须处理的其他一些限制是表视图中的项目数是动态的,这意味着它可以是任何数量,通常小于 10,我稍后将从 api 检索。并且单元格高度也是动态的,具体取决于内容。

我才刚刚开始写一些简单的代码

class ExampleViewController: UIViewController, UITableViewDelegate, UITableViewDataSource 
      @IBOutlet weak var tableView: UITableView!

  var items: [String] = [
    "Item 01", "Item 02", "Item 03", "Item 04", "Item 05",
    "Item 06", "Item 07", "Item 08", "Item 09", "Item 10"]

  override func viewDidLoad() 
    super.viewDidLoad()
    self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
  

  func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return self.items.count;
  

  func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
    let cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell")! as UITableViewCell
    cell.textLabel?.text = self.items[indexPath.row]
    return cell
  


【问题讨论】:

您是否尝试过 self.items.count*row_height 这将根据内容给出高度,但您也需要编写其他条件来检查屏幕高度 为什么不在tableview的页眉和页脚中添加顶部和底部的imageView? 页眉和页脚并没有真正起作用,因为顶部和底部的 imageView 只是视图的代表。实际上,它是一个包含更多组件、标签、图像和约束的视图。 尝试从底部和顶部布局指南的底部视图和顶部视图添加约束,并固定它们的高度,并将表格视图约束到它们各自的邻居,即顶部和底部。 你的意思是顶部和底部图像在视图上是静态的吗?因为如果它们在 屏幕 上是静态的,那么 tableView 必须始终保持不变。 【参考方案1】:

    将你的 UITableView 子类化以覆盖 intrinsicContentSize 为其 contentSize,如下所示:

    override var intrinsicContentSize: CGSize 
        return contentSize
    
    

    然后为您的表格使用自动行高,因此您的 exampleViewController 的 viewDidLoad 将具有:

    tableView.estimatedRowHeight = 44
    

    还有 UITableViewDelegate 函数:

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
        return UITableViewAutomaticDimension
    
    

    当您从 API 接收数据并重新加载表时,只需调用:

    tableView.invalidateIntrinsicContentSize()
    

    这将告诉您的表格将其自身调整为与其内容相同的大小(因为覆盖),并根据需要移动您的底部图像。


如果您的故事板抛出一个错误,指出您的 UIScrollView 的高度不明确,因为 UITableView 没有高度限制,请选择您的 UITableView 并在 Size Inspector 中为其指定占位符固有大小。

【讨论】:

太棒了!我真的不敢相信这不是 ios 的一部分。这不是一个非常常见的用例吗? 感谢@MartinMassera!我同意,我花了一段时间才弄清楚如何最好地做到这一点,但我现在已经多次使用这种方法了。我不想子类化,但我认为它仍然是最干净的,而不是手动更新约束。 太棒了!最佳解决方案【参考方案2】:

使用子类化技术的答案不完整。您还应该像这样覆盖layoutSubviews()

public class DynamicSizeTableView: UITableView

    override public func layoutSubviews() 
        super.layoutSubviews()
        if bounds.size != intrinsicContentSize 
            invalidateIntrinsicContentSize()
        
    

    override public var intrinsicContentSize: CGSize 
        return contentSize
    

【讨论】:

感谢您的帮助,但我想对此进行限制。如果 tableview 大小大于安全区域大小,那么我想启用滚动并且此效果停止。有可能吗?【参考方案3】:

更新 Swift 4 这段代码运行良好

self.scrollView.layoutIfNeeded()
self.view.layoutIfNeeded()
self.tableViewHeightConstraint.constant = CGFloat(self.tableView.contentSize.height)

【讨论】:

这个答案没有意义。【参考方案4】:

您需要将 IBOutlet 设置为设置 tableView 高度的NSLayoutConstraint(首先您需要创建具有任何值的高度约束,没关系),然后 ctrl 将其拖到您的类文件中

然后在您的viewWillAppear 中,您必须计算tableView 的高度并设置它。像这样:

var tableViewHeight:CGFloat = 0;
for (var i = tableView(self.tableView , numberOfRowsInSection: 0) - 1; i>0; i-=1 )
    tableViewHeight = height + tableView(self.tableView, heightForRowAtIndexPath: NSIndexPath(forRow: i, inSection: 0) )

tableViewHeightLayout.constant = tableViewHeight

差不多就是这样。这会给你的 scrollView 内容大小,并且不应该引发任何警告。

【讨论】:

【参考方案5】:

这是我在生产应用中使用的:

斯威夫特 5,2021 年

import UIKit

class DynamicTableView: UITableView 

    /// Will assign automatic dimension to the rowHeight variable
    /// Will asign the value of this variable to estimated row height.
    var dynamicRowHeight: CGFloat = UITableView.automaticDimension 
        didSet 
            rowHeight = UITableView.automaticDimension
            estimatedRowHeight = dynamicRowHeight
        
    

    public override var intrinsicContentSize: CGSize  contentSize 

    public override func layoutSubviews() 
        super.layoutSubviews()
        if !bounds.size.equalTo(intrinsicContentSize) 
            invalidateIntrinsicContentSize()
        
    

【讨论】:

【参考方案6】:

您可能必须实现表格视图的内在内容大小。请检查此answer 看看是否有帮助。

我记得有这个问题,甚至创建了一个自定义的UITableView 子类。

#import "IntrinsicTableView.h"

@implementation IntrinsicTableView

#pragma mark - UIView

- (CGSize)intrinsicContentSize

    return CGSizeMake(UIViewNoIntrinsicMetric, self.contentSize.height);


#pragma mark - UITableView

- (void)endUpdates

    [super endUpdates];
    [self invalidateIntrinsicContentSize];


- (void)reloadData

    [super reloadData];
    [self invalidateIntrinsicContentSize];


- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation

    [super reloadRowsAtIndexPaths:indexPaths withRowAnimation:animation];
    [self invalidateIntrinsicContentSize];


- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation

    [super reloadSections:sections withRowAnimation:animation];
    [self invalidateIntrinsicContentSize];


- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation

    [super insertRowsAtIndexPaths:indexPaths withRowAnimation:animation];
    [self invalidateIntrinsicContentSize];


- (void)insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation

    [super insertSections:sections withRowAnimation:animation];
    [self invalidateIntrinsicContentSize];


- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation

    [super deleteRowsAtIndexPaths:indexPaths withRowAnimation:animation];
    [self invalidateIntrinsicContentSize];


- (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation

    [super deleteSections:sections withRowAnimation:animation];
    [self invalidateIntrinsicContentSize];


@end

【讨论】:

【参考方案7】:

Swift 5 更新。添加 maxHeight 以便您可以指定您希望 tableView 的高度

class SelfSizingTableView: UITableView 
    var maxHeight = CGFloat.infinity

    override var contentSize: CGSize 
        didSet 
            invalidateIntrinsicContentSize()
            setNeedsLayout()
        
    

    override var intrinsicContentSize: CGSize 
        let height = min(maxHeight, contentSize.height)
        return CGSize(width: contentSize.width, height: height)
    

【讨论】:

i.stack.imgur.com/YcdkR.png .... 我该怎么做...并且这种效果停止。有可能吗? @Maulikshah 您可以尝试将view 高度减去safe area 高度并将其设置为tableView maxHeight。 tableView 将在达到其 maxHeight 时变为可滚动的。【参考方案8】:

在这种情况下,不要将底部单元格设为静态,使其成为表格视图的一部分,并使用表格视图委托方法将底部图像插入最后一行 - insertRowAtIndexPath

【讨论】:

【参考方案9】:

在这种情况下,将底部的 imageView(red) 添加到表格页脚视图中。

要在UITableView 中添加页脚视图,您可以使用:

tableViewObj.tableFooterView = footerViewObj;

【讨论】:

【参考方案10】:

也试试这个

in ViewDidLoad

 self.table.estimatedRowHeight = 44.0 ;
self.table.rowHeight = UITableViewAutomaticDimension;

索引路径处的行高

-(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
return UITableViewAutomaticDimension;

【讨论】:

【参考方案11】:

这里很简单。

第一步:为表格视图设置高度限制

第 2 步:控制拖动约束

第 3 步:在返回行数之前。在 numberOfRowsInSection 方法中,做

tableViewHeightConstraint.constant = tableView.rowHeight * CGFloat(someArray.count)

当然你可以通过编程方式编辑高度锚点,这里的逻辑是根据单元格高度和单元格数量来调整表格视图高度。

【讨论】:

【参考方案12】:

基于解决方案@nikans,用 Xamarin 编写

[Register(nameof(DynamicSizeTableView)), DesignTimeVisible(true)]
public class DynamicSizeTableView : UITableView

    public override void LayoutSubviews()
    
        base.LayoutSubviews();
        if (Bounds.Size != IntrinsicContentSize)
            InvalidateIntrinsicContentSize();
    

    public override CGSize IntrinsicContentSize => ContentSize;

    public DynamicSizeTableView(CGRect frame) : base(frame)  

    public DynamicSizeTableView(IntPtr handle) : base(handle)  

【讨论】:

【参考方案13】:

基于@rr1g0的解决方案

在 2020 年针对 Swift 5 进行了更新,并且也可以与带有部分的 TableViews 一起使用。

为 tableView 创建高度约束并为其创建一个出口。在 viewDidLayoutSubviews() 中使用以下代码:

var tableViewHeight: CGFloat = 0

for section in 0..<tableView.numberOfSections 
    for row in 0..<tableView.numberOfRows(inSection: section) 
        tableViewHeight += tableView(tableView, heightForRowAt: IndexPath(row: row, section: section))
    


tableViewHeightConstraint.constant = tableViewHeight

【讨论】:

不能调用非函数类型'UITableView?'的值 @zramled 你应该做错了什么。您的 tableView 属性是否命名为 tableView?你的网点设置正确吗? 当然。错误从这里开始' tableView(tableView, heightForRowAt: IndexPath( .....

以上是关于动态 UITableView 高度的主要内容,如果未能解决你的问题,请参考以下文章

动态 UITableView 单元格高度的问题

如何动态设置 UITableView 的高度?

实现 UITableView (Slave) 的动态高度,它作为子视图添加到另一个具有动态高度的 UITableView (Master) 的自定义单元格中

动态改变 UITableView 高度

动态 UITableView 高度与 UIScrollView 中的动态 UITableViewCells

嵌套 UITableView 动态高度