摘要 当在顶部插入新单元格时,具有动态单元格高度的UITableView会随机滚动。
详细说明 作为UITableViewController的一部分,为避免触发reloadData()和滚动时滚动不正确,我基于此堆栈溢出answer进行了以下工作:
var cellHeightsDictionary: [IndexPath: CGFloat] = [:]
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cellHeightsDictionary[indexPath] = cell.frame.size.height
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if let height = cellHeightsDictionary[indexPath] {
return height
}
return UITableView.automaticDimension
}
这很好,除了在数据源顶部添加新数据并触发reloadData()时。这样做时,我找不到合适的实现方式来防止表格随机滚动...这是我要解决的问题。
我尝试过的事情
我尝试使用更新前后contentSize之间的差异,然后更新滚动位置。不幸的是,基于我在Apple文档中所读的内容,使用动态单元格似乎无法信任contentSize且对我不起作用。尽管如此,这还是我的实现之一。
UIView.performWithoutAnimation {
//Detect exact position of the cell in relation to navBar
let navBar = navigationController?.navigationBar
let cellRectInTable = tableView.rectForRow(at: IndexPath(row: topArticle + countOfAddedItems, section: 0))
let positionVsNavBar = tableView.convert(cellRectInTable.origin, to: navBar)
let positionVsTop = tableView.convert(cellRectInTable.origin, to: tableView.superview)
let offsetOfCell = positionVsTop.y - positionVsNavBar.y
tableView.reloadData()
tableView.scrollToRow(at: IndexPath(row: topArticle + countOfAddedItems, section: 0), at: .top, animated: false)
tableView.contentOffset.y = tableView.contentOffset.y + offsetOfCell
}
我尝试在添加之前设置tableView.estimatedRowHeight = 0,tableView.estimatedSectionHeaderHeight = 0和tableView.estimatedSectionFooterHeight = 0,但似乎没有任何影响。
似乎最有效的方法是当我从cellHeightsDictionary获取单元格的高度并根据加法数对其求和时。这有时会完美无瑕,但有时却没有。另外,当添加许多行时,由于未在cellHeightsDictionary中找到值,它可能会崩溃。我尝试了多种变体,但没有使其起作用。同样重要的是,我不确定这为什么能给我最好的结果,所以我可能会遗漏一些明显的东西。我觉得在最后一个实现中的某个地方就是答案,但是我一直找不到它。
var iteratorCounter = 0
var heightCum = CGFloat(integerLiteral:0)
而iteratorCounter
iteratorCounter = iteratorCounter + 1
}
UIView.performWithoutAnimation {
tableView.reloadData()
tableView.layoutIfNeeded()
tableView.contentOffset.y = tableView.contentOffset.y + heightCum
}
我尝试了所有可以想到的事情,并在没有运气的情况下进行了搜索。任何帮助表示赞赏
感谢一百万!
答案 0 :(得分:1)
作为最后的选择,您可以将表格视图嵌入到新的滚动视图中,然后关闭表格视图的滚动。您可以完全控制滚动行为(尽管全部以编程方式进行)。
在这种情况下,我们必须添加一个与表视图高度相对应的布局约束,并为此约束添加一个出口。
如果单元格视图具有适当的布局,则可以使用systemLayoutSizeFittingSize
方法来计算确切的单元格高度。如果单元格具有多个标签(例如动态内容),请尝试使用固定宽度进行计算(在单元格中添加显式宽度约束)。
有了这个,我们可以重新加载表格视图,如下所示:
1)将数据插入数据源
2)重新计算内容高度
3)修改高度约束常量
4)致电layoutIfNeeded
5)重新加载表格视图
6)适当移动scrollview内容偏移=> setContentOffset(_ contentOffset: CGPoint, animated: Bool)
答案 1 :(得分:0)
定义一个变量:
describe('Protractor Login checing ', function() {
it('should add one and two', function() {
browser.get('http://localhost:4041/login');
element(by.model('username')).sendKeys('admin');
element(by.model('password')).sendKeys('admin');
element(by.id('login')).click();
browser.wait(waitForUrlChange("http://localhost:4041/dashboard", 8000, function(){
browser.getCurrentUrl().then(function (currentUrl) {
expect(currentUrl.toEqual("http://localhost:4041/dashboard"));
});
}));
});
function waitForUrlChange(url) {
return function () {
return browser.getCurrentUrl().then(function (currentUrl) {
console.log(currentUrl);
return url === currentUrl;
});
}
}
数量可以根据您的要求进行更改
并更新tableView的方法
var itemHeights = [CGFloat](repeating: UITableViewAutomaticDimension, count: 1000)
答案 2 :(得分:0)
最终成功运行的方法是:
步骤1。将UITableViewCell存储在导航栏下方的变量中,并存储该单元格相对于导航栏的偏移量。
第2步。插入单元格/ reloadData。
第3步:滚动到插入/重新加载之前保存的单元格,然后添加偏移量。
这是代码:
UIView.performWithoutAnimation {
//Step 1 Detect & Store
let topWillBeAt = getTopVisibleRow() + countOfAddedItems
let oldHeightDifferenceBetweenTopRowAndNavBar = heightDifferenceBetweenTopRowAndNavBar()
//Step 2 Insert
self.tableView.insertRows(at: arrayOfIndexPaths, with: .none)
//Step 3 Restore Scrolling
tableView.scrollToRow(at: IndexPath(row: topWillBeAt, section: 0), at: .top, animated: false)
tableView.contentOffset.y = tableView.contentOffset.y - oldHeightDifferenceBetweenTopRowAndNavBar
}
及支持功能:
func getTopVisibleRow () -> Int {
//We need this to accounts for the translucency below the nav bar
let navBar = navigationController?.navigationBar
let whereIsNavBarInTableView = tableView.convert(navBar!.bounds, from: navBar)
let pointWhereNavBarEnds = CGPoint(x: 0, y: whereIsNavBarInTableView.origin.y + whereIsNavBarInTableView.size.height + 1)
let accurateIndexPath = tableView.indexPathForRow(at: pointWhereNavBarEnds)
return accurateIndexPath?.row ?? 0
}
func heightDifferenceBetweenTopRowAndNavBar()-> CGFloat{
let rectForTopRow = tableView.rectForRow(at:IndexPath(row: getTopVisibleRow(), section: 0))
let navBar = navigationController?.navigationBar
let whereIsNavBarInTableView = tableView.convert(navBar!.bounds, from: navBar)
let pointWhereNavBarEnds = CGPoint(x: 0, y: whereIsNavBarInTableView.origin.y + whereIsNavBarInTableView.size.height)
let differenceBetweenTopRowAndNavBar = rectForTopRow.origin.y - pointWhereNavBarEnds.y
return differenceBetweenTopRowAndNavBar
}