如何从下往上填充 UITableView?
How to populate UITableView from the bottom upwards?
是否可以颠倒 tableView 的顺序。我已经搜索了很多解决方案,但所有结果都不是我想要实现的解决方案。他们都建议使用 scrollToRowAtIndexPath
滚动到 table 的最后位置并反向填充数据。但如果 table 内容是动态的,并且在某些情况下并非所有单元格都有数据,这就不起作用。例如在正常的table视图中顺序是:
标签 1
标签 2
标签 3
空
空
滚动方向
v
V
期望的结果是:
滚动方向
^
^
空
空
空
标签 3
标签 2
标签 1
在这个例子中,如果我使用 scrollToRowAtIndexPath
建议的方法并使用对象数组的长度,我只会得到从顶部数第三个单元格。最后得到这样的结果:
不需要的结果:
标签 3
标签 2
标签 1
空
空
滚动方向
v
V
任何帮助都将非常感谢。
如果您在 cellForRowAtIndexPath:
中显示了一个对象数组,假设您可以在 dataArray
中反转它,或者在 cellForRowAtIndexPath:
中
你可以这样做:
NSString *yourObject = dataArray[[dataArray count] - 1 - indexPath.row];
cell.textLabel.text = yourObject
我假设您将字符串保存在 dataArray 中。
填充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)
}
Swift3/4.0版本:
self.tableView.contentInset = UIEdgeInsetsMake(contentInsetTop, 0, 0, 0)
此解决方案使用 KVO 随着内容大小的变化调整内容插入。当滚动到顶部时,它还会考虑内容插入,因为简单地滚动到 CGPointZero
将滚动到内容的顶部,而不是滚动到 table.
的顶部
-(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];
}
}
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
我在 cellForRowAt 方法中做了:
let reverseIndex = myArray.count-indexPath.row-1
let currCellData = myArray.object(at: reverseIndex)
然后您继续使用 currCellData
这里是 KlimczakM 解决方案的改进解决方案,它适用于自动布局的表格视图单元格(以及固定的表格视图单元格)。此解决方案也适用于部分、部分页眉和部分页脚。
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)
}
注意:
以上代码未经测试但应该可以工作。
只要确保你能适应任何导航栏或标签栏的高度,你就会没事的。在上面的代码中,我只为导航栏这样做!
不用自己写代码了。
为什么不使用 ReverseExtension。它非常简单,会给你所有需要的结果。请关注这个 url
https://github.com/marty-suzuki/ReverseExtension
注意:每当您需要添加新单元格时,请将新添加的模型插入数据源数组的第零个索引处,因此新单元格应添加在底部。否则它会将单元格添加到顶部,您会再次感到困惑。
简单的方法就是像UILabel一样多行+自动布局。
-> UITableView 应该根据它的内容(又名内部布局)调整它的大小。
创建您的 table 视图并设置基础 class 以下内容:
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,这个条件保证table不会比它的父视图高。
第一个反向uitableview
tableView.transform = CGAffineTransformMakeScale (1,-1);
然后在单元格创建中反转单元格。
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
...
cell.contentView.transform = CGAffineTransformMakeScale (1,-1);
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
}
//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)
}
我希望每个新单元格都应该出现在 tableView 的底部,使用这个:-
- 反转表格视图:
myTableView.transform = CGAffineTransform (scaleX: -1,y: -1)
- 同时反转单元格:
cell.contentView.transform = CGAffineTransform (scaleX: -1,y: -1)
- 现在以相反的方向填充您的 tabelViewDataSource,就像您使用数组一样,那么您可以这样做:
myTableViewData.insert(<Your New Array Element>), at: 0)
是否可以颠倒 tableView 的顺序。我已经搜索了很多解决方案,但所有结果都不是我想要实现的解决方案。他们都建议使用 scrollToRowAtIndexPath
滚动到 table 的最后位置并反向填充数据。但如果 table 内容是动态的,并且在某些情况下并非所有单元格都有数据,这就不起作用。例如在正常的table视图中顺序是:
标签 1
标签 2
标签 3
空
空
滚动方向
v
V
期望的结果是:
滚动方向
^
^
空
空
空
标签 3
标签 2
标签 1
在这个例子中,如果我使用 scrollToRowAtIndexPath
建议的方法并使用对象数组的长度,我只会得到从顶部数第三个单元格。最后得到这样的结果:
不需要的结果:
标签 3
标签 2
标签 1
空
空
滚动方向
v
V
任何帮助都将非常感谢。
如果您在 cellForRowAtIndexPath:
中显示了一个对象数组,假设您可以在 dataArray
中反转它,或者在 cellForRowAtIndexPath:
中
你可以这样做:
NSString *yourObject = dataArray[[dataArray count] - 1 - indexPath.row];
cell.textLabel.text = yourObject
我假设您将字符串保存在 dataArray 中。
填充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)
}
Swift3/4.0版本:
self.tableView.contentInset = UIEdgeInsetsMake(contentInsetTop, 0, 0, 0)
此解决方案使用 KVO 随着内容大小的变化调整内容插入。当滚动到顶部时,它还会考虑内容插入,因为简单地滚动到 CGPointZero
将滚动到内容的顶部,而不是滚动到 table.
-(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];
}
}
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
我在 cellForRowAt 方法中做了:
let reverseIndex = myArray.count-indexPath.row-1
let currCellData = myArray.object(at: reverseIndex)
然后您继续使用 currCellData
这里是 KlimczakM 解决方案的改进解决方案,它适用于自动布局的表格视图单元格(以及固定的表格视图单元格)。此解决方案也适用于部分、部分页眉和部分页脚。
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)
}
注意:
以上代码未经测试但应该可以工作。 只要确保你能适应任何导航栏或标签栏的高度,你就会没事的。在上面的代码中,我只为导航栏这样做!
不用自己写代码了。 为什么不使用 ReverseExtension。它非常简单,会给你所有需要的结果。请关注这个 url https://github.com/marty-suzuki/ReverseExtension
注意:每当您需要添加新单元格时,请将新添加的模型插入数据源数组的第零个索引处,因此新单元格应添加在底部。否则它会将单元格添加到顶部,您会再次感到困惑。
简单的方法就是像UILabel一样多行+自动布局。 -> UITableView 应该根据它的内容(又名内部布局)调整它的大小。 创建您的 table 视图并设置基础 class 以下内容:
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,这个条件保证table不会比它的父视图高。
第一个反向uitableview
tableView.transform = CGAffineTransformMakeScale (1,-1);
然后在单元格创建中反转单元格。
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
...
cell.contentView.transform = CGAffineTransformMakeScale (1,-1);
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
}
//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)
}
我希望每个新单元格都应该出现在 tableView 的底部,使用这个:-
- 反转表格视图:
myTableView.transform = CGAffineTransform (scaleX: -1,y: -1)
- 同时反转单元格:
cell.contentView.transform = CGAffineTransform (scaleX: -1,y: -1)
- 现在以相反的方向填充您的 tabelViewDataSource,就像您使用数组一样,那么您可以这样做:
myTableViewData.insert(<Your New Array Element>), at: 0)