如何使用autolayout将UIScrollView滚动到viewWillAppear的底部,没有可视化动画
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用autolayout将UIScrollView滚动到viewWillAppear的底部,没有可视化动画相关的知识,希望对你有一定的参考价值。
这是问题所在:
我在UIScrollView中放了一堆视图。这些子视图的大小和位置由约束定义。这非常有效,滚动效果也很好。到现在为止还挺好。
但是,当我第一次在屏幕上显示viewcontroller时,我希望我的scrollview一直滚动到底部,这就是麻烦开始的地方。为了知道底部的位置,我需要知道子视图中最低元素的位置和大小。也应该很容易(因为我在某处提到了UIView):得到UIView的框架并且瞧。
我想在滚动视图出现在屏幕上之前将其滚动到底部(基本上,在viewWillAppear :)中,但是仅在viewWillAppear之后和viewDidAppear:之前调用约束。
在viewWillAppear中获取UIView框架给了我一个零大小的CGRect。在viewDidAppear中做同样的事情给了我正确的CGRect。但是viewDidAppear对我来说太迟了,因为滚动视图已经在屏幕上,所以你看到内容向上移动。
有没有人有这个很好的解决方案?我尝试将代码放在viewDidLayoutSubviews中,但这也不起作用。
viewWillAppear
的问题在于它在布局发生之前被调用。您必须在布局后调整滚动视图的内容偏移量 - 使用viewDidLayoutSubviews
方法。在这是我的解决方案:
@property (nonatomic, assign) BOOL shouldScrollToBottom;
- (void)viewDidLoad
{
[super viewDidLoad];
_shouldScrollToBottom = YES;
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
// Scroll table view to the last row
if (_shouldScrollToBottom)
{
_shouldScrollToBottom = NO;
[_scrollView setContentOffset:CGPointMake(0, CGFLOAT_MAX)];
}
}
这就是我所做的,它适用于我(通过自动布局计算的单元格高度):
class MessagesTableViewController: UITableViewController
{
var shouldScrollToBottom = false
override func viewDidLoad()
{
super.viewDidLoad()
...
shouldScrollToBottom = true
}
override func viewDidLayoutSubviews()
{
super.viewDidLayoutSubviews()
if(shouldScrollToBottom == true)
{
shouldScrollToBottom = false
goToBottom()
}
}
private func goToBottom()
{
if(data.count == 0)
{
return
}
let indexPath = NSIndexPath(forRow: tableView.numberOfRowsInSection(0)-1, inSection: 0)
tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Bottom, animated: false)
}
}
我也遇到了这个问题!在viewDidAppear()
之前,视图没有滚动到所需的页面。 viewDidLayoutSubviews()
有多个子视图,所以在这个函数中做一次,like Thomas suggested,对我来说也不起作用。但是,如果你使用一个小技巧,viewDidLayoutSubviews()
方法是有效的:
每次在创建视图期间调用viewDidLayoutSubviews()
时,您都需要尝试滚动到所需的点。然后,在显示视图后,您不再希望再调用它。因此,在初始布局之后添加在viewDidAppear()
中更改的控制变量。这是完整的例子:
var needsFirstScroll = true
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if(needsFirstScroll) {
var frame = CGRect() // placeholder, do your frame calculation here
scrollView.scrollRectToVisible(frame, animated: false)
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
needsFirstScroll = false
}
我最终提出的解决方案是:
- 将scrollview的所有子视图存储在1个contentview中,而不是直接作为scrollview的子视图
- 观察内容视图的界限何时发生变化
- 每次他们改变时都会将
scrollRectToVisible
放到scrollview的底部 - 检测到
scrollViewWillBeginDragging
委托调用后立即禁用自动滚动到底部,以便在用户开始移动滚动视图时停止自动滚动
我找到了解决这个问题的方法,这可能对未来的访问者有用。在尝试滚动之前,需要在viewWillAppear中加载tableView。
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.tableView reloadData];
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:[self.tableView.numberOfRowsInSection:0] inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:animated];
}
以上是关于如何使用autolayout将UIScrollView滚动到viewWillAppear的底部,没有可视化动画的主要内容,如果未能解决你的问题,请参考以下文章
使用 AutoLayout,当导航栏消失时,如何将 UILabel 保持在同一位置?
如何在 UIScrollView 内使用 Autolayout 将 UIImage 视图缩放为正方形
AutoLayout:如何将 UIView 限制为不高于包含其所有子视图所需的高度?