4

我试图复制 iOS 应用程序Rdio中看到的屏幕大小调整行为。有问题的屏幕提供了所选专辑的概览,并包含上半部分的 UIView 和下半部分的 UITableView。当 tableView 滚动时,它首先向上调整大小以填充屏幕,然后在达到最大高度后开始正常滚动其内容。

经过一番搜索,我发现了这个问题:Dragging UITableView这基本上要求相同的东西,但是它接受的方法与我最初的想法和试验相同,即使用 UIPanGestureRecognizer 并根据翻译调整 tableviews 的高度平底锅。

这不提供我正在寻找的行为。使用此方法仅允许您静态地向上或向下拖动 tableviews 的高度,并且它增加了 panGesture 覆盖 tableViews 的问题,从而阻止滚动内容。

Rdio 应用程序的大小调整行为功能和感觉就像UIScrollView,它具有惯性。您可以一直拖动它,向上或向下轻弹它,它可以平滑地调整大小。当 tableView 达到其全尺寸或原始一半尺寸时,剩余的惯性似乎传递到 tableview 上,导致单元格像通常那样滚动。我知道他们一定是在操纵 UIScrollViews,我只是不知道怎么做。

最后一点,最终我将在这个屏幕上使用 AutoLayout,所以我想知道这将如何潜在地阻碍或帮助这种情况。

更新

这种方法让我最接近我目前正在寻找的行为。向上轻弹 tableView 的行为与我想要的完全一样(用惯性调整大小并在达到最大高度时继续滚动),尽管灵敏度比我想要的要低。然而,向下轻弹不会产生惯性并立即停止。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGRect scrollViewFrame = scrollView.frame;
    CGFloat scrollViewYOffset = scrollView.contentOffset.y;

    if (scrollViewFrame.origin.y <= kTableViewMaxYOrigin || scrollViewFrame.origin.y <= _originalTableViewFrame.origin.y)
    {
        scrollViewFrame.origin.y -= scrollViewYOffset;

        if(scrollViewFrame.origin.y >= kTableViewMaxYOrigin && scrollViewFrame.origin.y <= _originalTableViewFrame.origin.y)
        {
            scrollViewFrame.size.height += scrollViewYOffset;
            scrollView.frame = scrollViewFrame;
            scrollView.contentOffset = CGPointZero;
        }
    }
}
4

3 回答 3

5

我制作了一个使用自动布局的版本。我花了一段时间的反复试验才把这个弄对了!

请使用评论并问我答案是否不清楚。

viewDidLoad保存布局约束的初始高度时,确定您希望滚动视图成为的最低点。

- (void)viewDidLoad
{
    ...
    _initialTopLayoutConstraintHeight = self.topLayoutConstraint.constant;
    ...
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    BOOL leaveScrollAlone = self.topLayoutConstraint.constant == _initialTopLayoutConstraintHeight && scrollView.contentOffset.y <= 0;
    if (leaveScrollAlone)
    {
        // This allows for bounce when swiping your finger downwards and reaching the stopping point
        return;
    }

    // Do some capping of that layout constraint to keep it from going past the range you want it to be.
    // In this case, I use self.topLayoutGuide.length so that my UICollectionView scales all the way until
    // it hits the bottom of the navigation bar
    CGFloat topLayoutConstraintLength =   _initialTopLayoutConstraintHeight - scrollView.contentInset.top;
    topLayoutConstraintLength           = MAX(topLayoutConstraintLength, self.topLayoutGuide.length);
    topLayoutConstraintLength           = MIN(topLayoutConstraintLength, _initialTopLayoutConstraintHeight);
    self.topLayoutConstraint.constant   = topLayoutConstraintLength;


    // Keep content seemingly still while the UICollectionView resizes
    if (topLayoutConstraintLength > self.topLayoutGuide.length)
    {
        scrollView.contentInset = UIEdgeInsetsMake(scrollView.contentInset.top + scrollView.contentOffset.y,
                                                   scrollView.contentInset.left,
                                                   scrollView.contentInset.bottom,
                                                   scrollView.contentInset.right);

        scrollView.contentOffset = CGPointZero;
    }

    // This helps get rid of the extraneous contentInset.top we accumulated for keeping
    // the content static while the UICollectionView resizes
    if (scrollView.contentOffset.y < 0)
    {
        self.topLayoutConstraint.constant -= scrollView.contentOffset.y;

        scrollView.contentInset = UIEdgeInsetsMake(scrollView.contentInset.top + scrollView.contentOffset.y,
                                                   scrollView.contentInset.left,
                                                   scrollView.contentInset.bottom,
                                                   scrollView.contentInset.right);
    }

    // Prevents strange jittery artifacts
    [self.view layoutIfNeeded];
}
于 2013-09-27T21:42:33.877 回答
3

事实证明,在两个方向上获得平滑的惯性调整大小的关键组件是通过其 contentOffset.y 更新滚动视图 contentInset.top。

我相信这回想起来是有道理的,好像里面的内容已经在顶部它不能再滚动了,因此突然停止而不是平滑滚动。至少这是我的理解。

另一个关键点是确保单元格仅在达到最大或原始高度后才开始滚动。每次调整视图大小直到达到最大或原始高度时,只需将 scrollViews contentOffset 设置为 CGPointZero 即可完成此操作。

这是- (void)scrollViewDidScroll:(UIScrollView *)scrollView演示如何实现此效果的方法。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGRect scrollViewFrame = scrollView.frame;
    CGFloat scrollViewTopContentInset = scrollView.contentInset.top;
    CGFloat scrollViewYOffset = scrollView.contentOffset.y;

    if (scrollViewFrame.origin.y <= kTableViewMaxYOrigin || scrollViewFrame.origin.y <= _originalTableViewFrame.origin.y)
    {
        scrollViewFrame.origin.y -= scrollViewYOffset;

        if(scrollViewFrame.origin.y >= kTableViewMaxYOrigin && scrollViewFrame.origin.y <= _originalTableViewFrame.origin.y)
        {
            scrollViewFrame.size.height += scrollViewYOffset;
            scrollViewTopContentInset += scrollViewYOffset;
            scrollView.frame = scrollViewFrame;
            scrollView.contentInset = UIEdgeInsetsMake(scrollViewTopContentInset, 0, 0, 0);
            scrollView.contentOffset = CGPointZero;
        }
    }
}
于 2013-09-09T15:44:04.440 回答
0

我还没有看到有问题的应用程序,但是根据您的描述......在您tableView的委托方法-scrollViewDidScroll:中,设置tableView.frame.origin.yalbumView.frame.height - tableView.contentOffset.y并相应地更改其高度。

(如果您使用自动布局,则必须更改与 tableView 的框架相关的约束,而不是框架本身。)

于 2013-09-08T19:01:30.623 回答