簡體   English   中英

如何將 UITableViewCell 對齊到 UITableView 的底部?

[英]How to align UITableViewCell to the bottom of the UITableView?

當您使用insertRowsAtIndexPaths:withRowAnimation:插入第一個UITableViewCell時,它通常出現在UITableView的頂部。 Periscope 應用程序中,情況正好相反 - 第一個插入的單元格底部對齊。 隨着新單元格被推入,舊單元格在表格中向上移動。 這是如何實現的?

在此處輸入圖片說明

如果您對我在 Periscope iOS 應用程序中的做法感興趣,那實際上非常簡單……

TL; 博士; 添加一個透明的表格標題標題視圖,其高度等於表格視圖框架的高度。 然后,當您向表格添加單元格時,只需為表格視圖的內容偏移設置動畫。

給你的表視圖一個標題視圖:

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    UIView *headerView = [[UIView alloc] initWithFrame:CGRectZero];
    headerView.userInteractionEnabled = NO; // all touches within this space must go through to the video layer

    return headerView;   // empty header above chat, so messages flow in from bottom
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return self.tableView.frame.size.height;            // empty header above chat, so messages flow in from bottom
}

將數據添加到您的表中(在我的例子中,消息被添加到一個名為 _messages 的數組中。然后我在 UITableViewController 上調用 reloadData)。 然后調用此方法為以下單元格設置動畫:

- (void)scrollTableToBottom
{
    if (!self.isViewLoaded || _messages.count == 0)
        return;

    CGFloat offsetY = self.tableView.contentSize.height - self.tableView.frame.size.height + self.tableView.contentInset.bottom;

    [UIView animateWithDuration:0.33
            delay:0
            options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionAllowUserInteraction
            animations:^{
                [self.tableView setContentOffset:CGPointMake(0, offsetY) animated:NO];
            }
            completion:nil];
}

希望有幫助。 我發現這是一種非常便宜/簡單的模擬錨定在底部的細胞的方法。 我知道有些人提到過把桌子倒過來,但這對我來說似乎很瘋狂。 :-)

Aaron Wasserman 的 Swift 4 版本回答。

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let headerView = UIView(frame: .zero)
    headerView.isUserInteractionEnabled = false
    return headerView
}

// Added logic to avoid blank space at the top
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return tableView.frame.size.height - CGFloat(messages.count * cellHeight)
}

 func scrollToBottom(animated: Bool) {
    if isViewLoaded && messages.count > 0 {

        let offset = tableView.contentSize.height - tableView.frame.size.height + tableView.contentInset.bottom

        UIView.animate(withDuration: 0.33, delay: 0, options: [.curveEaseOut, .allowUserInteraction], animations: {
            self.tableView.setContentOffset(CGPoint(x: 0, y: offset), animated: animated)
        }, completion: nil)
    }
}

需要在 tableView.reloadData() 之后調用 scrollToBottom 方法

我對 Mr.Wasserman 回答的修改

extension MyViewController : UITableViewDelegate {

  func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
      return UITableView.automaticDimension
  }

  func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
      let headerView = UIView(frame: .zero)
      headerView.isUserInteractionEnabled = false
      return headerView
  }

  func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
      let diff = tableView.contentSize.height - tableView.bounds.height
      return diff > 0 ? 0 : -diff
  }

}

您可以使用 insertRowsAtIndexPath 方法,然后讓 tableview 滾動到底部。

[self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:self.posts.count-1 inSection:0]] withRowAnimation:UITableViewRowAnimationBottom];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];

如果你希望在你的 tableview 頂部有那個巨大的間隙,你可以設置滾動偏移,並在新項目進來時調整它。

另一種方法是將 tableview 倒置,然后將每一行倒置。

聚會有點晚了,但這是另一種方法。 無需添加任意標題視圖即可完成。 每當內容大小發生變化時,調整內容偏移量。

class BottomEndianTableView: UITableView {

    private var observer: Any?

    override init(frame: CGRect, style: UITableView.Style) {
        super.init(frame: frame, style: style)
        commonInit()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }

    private func commonInit() {
        observer = observe(\.contentSize) { _, _ in
            DispatchQueue.main.async { [weak self] in
                self?.scrollToEnd(animated: false)
            }
        }
    }

    func scrollToEnd(animated: Bool) {
        let scrollDistance = contentSize.height - frame.height
        setContentOffset(CGPoint(x: 0, y: scrollDistance), animated: animated)
    }

}

您還可以調用scrollToEnd(animated: true)以響應鍵盤顯示

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM