如何使用autolayout将UIScrollView滚动到viewWillAppear的底部,没有可视化动画

大道之行,天下为公。这篇文章主要讲述如何使用autolayout将UIScrollView滚动到viewWillAppear的底部,没有可视化动画相关的知识,希望能为你提供帮助。
这是问题所在:
【如何使用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 = falseoverride 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 = trueoverride 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]; }


    推荐阅读