【问题标题】:Dynamic UITableView height动态 UITableView 高度
【发布时间】: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 必须始终保持不变。

标签: ios swift uitableview


【解决方案1】:
  1. 将你的 UITableView 子类化以覆盖 intrinsicContentSize 为其 contentSize,如下所示:

    override var intrinsicContentSize: CGSize {
        return contentSize
    }
    
  2. 然后为您的表格使用自动行高,因此您的 exampleViewController 的 viewDidLoad 将具有:

    tableView.estimatedRowHeight = 44
    

    还有 UITableViewDelegate 函数:

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
    }
    
  3. 当您从 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( .....
                  猜你喜欢
                  • 2012-09-08
                  • 1970-01-01
                  • 2012-12-22
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-01-13
                  • 2020-02-07
                  • 2014-09-30
                  相关资源
                  最近更新 更多