【问题标题】:How to populate UITableView from the bottom upwards?如何从底部向上填充 UITableView?
【发布时间】:2015-03-22 06:08:43
【问题描述】:

是否可以反转 tableView 的顺序。我已经搜索了很多解决方案,但所有结果都不是我想要实现的解决方案。他们都建议使用scrollToRowAtIndexPath 滚动到表格的最后一个位置并反向填充数据。但如果表格内容是动态的并且在某些情况下并非所有单元格都有数据,这将不起作用。例如在普通的 tableView 中,顺序是:


标签 1

标签 2

标签 3

滚动方向
v
V


期望的结果是:
滚动方向
^
^

标签 3

标签 2

标签 1


在这个例子中,如果我使用scrollToRowAtIndexPath 的建议方法并使用对象数组的长度,我只会得到顶部的第三个单元格。最后得到这样的结果:


不想要的结果:

标签 3

标签 2

标签 1

滚动方向
v
V


任何帮助都会非常感谢。

【问题讨论】:

  • 我不明白这个问题。为什么底部有空行?您如何在内部表示这些空行?
  • 一个 HACKY 解决方案是翻转表格视图,并翻转表格视图中的每个单元格。这样,您可以正常填充表格,第一个单元格将出现在底部。最简单的方法,恕我直言。
  • @kai Taylor 我的代码有一个小错误,请立即尝试。
  • cell.setTitle.text = myArray.reversed()[indexPath.row] 反转你的数组就可以了。

标签: ios objective-c iphone uitableview ios8


【解决方案1】:

我希望每个新单元格都应该从 tableView 的底部出现,使用这个:-

  1. 反转表格视图: myTableView.transform = CGAffineTransform (scaleX: -1,y: -1)
  2. 也反转单元格: cell.contentView.transform = CGAffineTransform (scaleX: -1,y: -1)
  3. 现在以相反的方向填充您的 tabelViewDataSource,就像您使用数组一样,那么您可以这样做: myTableViewData.insert(<Your New Array Element>), at: 0)

【讨论】:

    【解决方案2】:
         //Add these lines where you want to reload your tableView  
    let indexpath = IndexPath(row: self.Array.count-1, section: 0)
                                    self.tableView.scrollToRow(at: indexpath, at: .top, animated: true)
                                    self.updateTableContentInset()
        
        
        
        //Add this function below
        func updateTableContentInset() {
            let numRows = self.tableView.numberOfRows(inSection: 0)
            var contentInsetTop = self.tableView.bounds.size.height
            for i in 0..<numRows {
                let rowRect = self.tableView.rectForRow(at: IndexPath(item: i, section: 0))
                contentInsetTop -= rowRect.size.height
                if contentInsetTop <= 0 {
                    contentInsetTop = 0
                    break
                }
            }
            self.tableView.contentInset = UIEdgeInsets(top: contentInsetTop,left: 0,bottom: 0,right: 0)
        }
    

    【讨论】:

      【解决方案3】:

      从底部填充UITableView

      - (void)updateTableContentInset {
          NSInteger numRows = [self.tableView numberOfRowsInSection:0];
          CGFloat contentInsetTop = self.tableView.bounds.size.height;
          for (NSInteger i = 0; i < numRows; i++) {
              contentInsetTop -= [self tableView:self.tableView heightForRowAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
              if (contentInsetTop <= 0) {
                  contentInsetTop = 0;
                  break;
              }
          }
          self.tableView.contentInset = UIEdgeInsetsMake(contentInsetTop, 0, 0, 0);
      }
      

      要颠倒元素的顺序:

      dataSourceArray = dataSourceArray.reverseObjectEnumerator.allObjects;
      

      Swift 4.2/5 版本:

      func updateTableContentInset() {
          let numRows = self.tableView.numberOfRows(inSection: 0)
          var contentInsetTop = self.tableView.bounds.size.height
          for i in 0..<numRows {
              let rowRect = self.tableView.rectForRow(at: IndexPath(item: i, section: 0))
              contentInsetTop -= rowRect.size.height
              if contentInsetTop <= 0 {
                  contentInsetTop = 0
                  break
              }
          }
          self.tableView.contentInset = UIEdgeInsets(top: contentInsetTop,left: 0,bottom: 0,right: 0)
      }
      

      Swift 3/4.0 版本:

      self.tableView.contentInset = UIEdgeInsetsMake(contentInsetTop, 0, 0, 0)
      

      【讨论】:

      • 抱歉,您的回答非常好,我可以根据自己的需要调整它,有无标题。我只是想我会为那些使用默认标题设置(高度为 20 的空白标题)的人指出这个问题,以供将来可能遇到此答案的任何人使用,他们可能不明白为什么他们会获得额外的填充。再次感谢。
      • 不幸的是,当您在具有动态高度的 UITableViewCells 上使用 AutoLayout 时,此解决方案将不起作用。
      • 任何适用于自动布局/动态单元格高度的解决方案?
      • 自 3.0 以来语法和逻辑发生了变化?我得到:Cannot call value of non-function type 'UITableView!'syntax changed 行:tableView(self.tableView, heightForRowAt: IndexPath(item: i, section: 0))
      • @RomanVasilyev 你是对的 - 我已经更新了答案。谢谢!
      【解决方案4】:

      Swift 4.0 和 4.2 版本

      viewDidLoad中的第一个反向UITableView

      override func viewDidLoad() {
              super.viewDidLoad()
              tableView.transform = CGAffineTransform(scaleX: 1, y: -1)
      }
      

      然后反转cellForRowAt中的单元格。

      func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
              guard let cell = tableView.dequeueReusableCell(withIdentifier: "MyTableViewCell", for: indexPath) as? MyTableViewCell else { fatalError() }
      
              cell.contentView.transform = CGAffineTransform(scaleX: 1, y: -1)
              return cell
          }
      

      【讨论】:

      • 您的解决方案是正确的,但删除选项没有改变。如果您有解决方案,请帮帮我吗?
      • 我不明白你的问题,你能详细说明你的问题吗?
      • 请看这张图片,你会发现删除看起来很奇怪。 imgur.com/D9x2KG7
      • 如您所知,我们正在转换单元格内容,因此它应该转换单元格中的所有内容。
      • 很好,如果键盘出现就可以了
      【解决方案5】:

      第一个反向uitableview

          tableView.transform = CGAffineTransformMakeScale (1,-1);
      

      然后在单元格创建中反转单元格。

      - (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
      
          ...
      
          cell.contentView.transform = CGAffineTransformMakeScale (1,-1);
      

      【讨论】:

      • 这是一个简单的解决方案
      【解决方案6】:

      简单的方法是使用像 UILabel 多行 + 自动布局。 -> UITableView 应该根据它的内容(又名内在布局)调整它的大小。 创建您的 tableview 并设置以下基类:

      class IntrinsicTableView: UITableView {
      
      override var contentSize:CGSize {
          didSet {
              self.invalidateIntrinsicContentSize()
          }
      }
      
      override var intrinsicContentSize: CGSize {
          self.layoutIfNeeded()
          return CGSize(width: UIViewNoIntrinsicMetric, height: contentSize.height)
      }
      

      }

      现在为您的 tableview 引脚设置左右和底部布局约束到它的父视图。 最重要的是顶部布局约束应该设置为大于或等于0,这个条件保证表不会比它的父视图高。

      【讨论】:

        【解决方案7】:

        不要费心自己编写代码。 为什么不使用 ReverseExtension。它非常简单,会给你所有需要的结果。请关注这个网址 https://github.com/marty-suzuki/ReverseExtension

        注意: 每当您需要添加新单元格时,请在数据源数组的第零个索引处插入新添加的模型,因此新单元格应添加在底部。否则它会将单元格添加到顶部,您会再次感到困惑。

        【讨论】:

        • CollectionView 的任何解决方案?
        • @aaban 这个库是关于内容插图的开放问题。你能帮我解决这个问题吗?我无法设置表格视图的底部插图。
        【解决方案8】:

        这里是 KlimczakM 解决方案的改进解决方案,适用于自动布局的 tableview 单元格(以及固定的单元格)。此解决方案也适用于部分、部分页眉和部分页脚。

        Swift 3.0

        func updateTableContentInset(forTableView tv: UITableView) {
            let numSections = tv.numberOfSections
            var contentInsetTop = tv.bounds.size.height -
                (self.navigationBar?.frame.size.height ?? 0)
        
            for section in 0..<numSections {
                let numRows = tv.numberOfRows(inSection: section)
                let sectionHeaderHeight = tv.rectForHeader(inSection: section).size.height
                let sectionFooterHeight = tv.rectForFooter(inSection: section).size.height
                contentInsetTop -= sectionHeaderHeight + sectionFooterHeight
                for i in 0..<numRows {
                    let rowHeight = tv.rectForRow(at: IndexPath(item: i, section: section)).size.height
                    contentInsetTop -= rowHeight
                    if contentInsetTop <= 0 {
                        contentInsetTop = 0
                        break
                    }
                }
                // Break outer loop as well if contentInsetTop == 0
                if contentInsetTop == 0 {
                    break
                }
            }
            tv.contentInset = UIEdgeInsetsMake(contentInsetTop, 0, 0, 0)
        }
        

        注意:

        以上代码未经测试,但应该可以工作。 只要确保你能适应任何导航栏或标签栏的高度,你就会没事的。在上面的代码中,我只对导航栏这样做!

        【讨论】:

          【解决方案9】:

          Swift 3.01 - 其他解决方案可以是,旋转和翻转 tableView。

          self.tableView.transform = CGAffineTransform.init(rotationAngle: (-(CGFloat)(M_PI)))
          self.tableView.transform = CGAffineTransform.init(translationX: -view.frame.width, y: view.frame.height)
          

          UITableView anchor rows to bottom

          【讨论】:

            【解决方案10】:

            我在 cellForRowAt 方法中做过:

            let reverseIndex = myArray.count-indexPath.row-1
            
            let currCellData = myArray.object(at: reverseIndex) 
            

            然后你继续使用 currCellData

            【讨论】:

              【解决方案11】:

              此解决方案使用 KVO随着内容大小的变化调整内容插入。它还会在滚动到顶部时考虑内容插入,因为只需滚动到 CGPointZero 将滚动到内容的顶部,而不是滚动到表格的顶部。

              -(void)startObservingContentSizeChanges
              {
                  [self.tableView addObserver:self forKeyPath:kKeyPathContentSize options:0 context:nil];
              }
              
              -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
              {
                  if([keyPath isEqualToString:kKeyPathContentSize] && object == self.tableView)
                  {
                      // difference between content and table heights. +1 accounts for last row separator
                      CGFloat height = MAX(self.tableView.frame.size.height - self.tableView.contentSize.height, 0) + 1;
              
                      self.tableView.contentInset = UIEdgeInsetsMake(height, 0, 0, 0);
              
                      // "scroll" to top taking inset into account
                      [self.tableView setContentOffset:CGPointMake(0, -height) animated:NO];
              
                  }
              }
              

              【讨论】:

                【解决方案12】:

                如果你有一个对象数组显示在cellForRowAtIndexPath:,比如说dataArray,你可以反转它,或者在cellForRowAtIndexPath: 你可以这样做:

                NSString *yourObject = dataArray[[dataArray count] - 1 - indexPath.row];
                cell.textLabel.text = yourObject
                

                我假设您将字符串保存在 dataArray 中。

                【讨论】:

                • 这种方法将给出我在第三个示例中显示的结果。顺序会颠倒,但不会从表格视图的物理底部开始。
                猜你喜欢
                • 1970-01-01
                • 2018-11-23
                • 2023-03-16
                • 1970-01-01
                • 1970-01-01
                • 2019-12-29
                • 1970-01-01
                • 2018-12-15
                • 1970-01-01
                相关资源
                最近更新 更多