调整UITableView的大小,如Rdio iOS应用程序中所示

时间:2013-09-08 16:17:18

标签: ios objective-c uitableview uiscrollview

我试图复制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;
        }
    }
}

3 个答案:

答案 0 :(得分:5)

我制作了一个使用autolayout的版本。 我花了一段时间的试验和错误才能使这一次正确!

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

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];
}

答案 1 :(得分:3)

事实证明,在两个方向上进行平滑惯性调整的关键组件是通过其contentOffset.y更新scrollViews 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;
        }
    }
}

答案 2 :(得分:0)

我没有看到有问题的应用,但是根据您的说明...在tableView的委托方法-scrollViewDidScroll:中,将tableView.frame.origin.y设置为albumView.frame.height - tableView.contentOffset.y并且相应地改变它的高度。

(如果你正在使用autolayout,你将不得不改变与tableView的框架有关的约束而不是框架本身。)