如何使用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 限制为不高于包含其所有子视图所需的高度?

如何使用水平滚动以编程方式执行 AutoLayout?

如何使用 autoLayouts 动态增加 UIScrollView 的高度

如何使用 AutoLayout 制作均匀分布的图像行? [复制]