将UITableView滑动到屏幕上,继续滑动?

时间:2014-08-25 13:33:22

标签: ios objective-c uitableview uiscrollview

我想要一个从屏幕外开始的桌面视图,可以在屏幕上滚动,到达顶部,并继续滚动。我已经在下面看到了所需的互动。

我尝试过两件事,但两件事都不像我需要的那样。

我做的第一件事是将tableview放在scrollview中,并在tableview上检测到平移时移动scrollview。这会阻止tableview中的触摸,即使我可以检测到tableview何时触到屏幕顶部,我也不确定如何继续滚动。

我尝试的第二件事是将scrollview的内容大小设置为tableview的高度。这让tableview滚动,但我似乎只能在标记为“List Item 1”的初始小矩形中接收触摸。当桌面滚动时,我无法抓住中间并再滚动它。

构建此互动的最佳方式是什么? 修改:地图将此底部视图围绕在左侧,右侧和大部分顶部。拉起底部视图时,地图左右可见。

1。)
1

2。)
2

3。)(这会继续滚动列表中的项目数量。)
3

3 个答案:

答案 0 :(得分:17)

我猜你想要这样的东西:

small list

或者这个:

big list

我在地图视图上显示了我的表格视图。我像这样设置了表格视图的contentInsetcontentOffset

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tableView.rowHeight = 44;
}

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    self.tableView.contentInset = (UIEdgeInsets){ .top = self.view.bounds.size.height - self.tableView.rowHeight };
    self.tableView.contentOffset = CGPointMake(0, -self.tableView.contentInset.top);
}

请注意,虽然默认行高为44,但tableView.rowHeight除非您明确设置,否则返回-1。 (在故事板中将其设置为44不会改变这一点。)

我使用了UITableView的子类,其中我做了两件事:

  1. 我明确设置了self.backgroundColor = [UIColor clearColor]。我发现在故事板中设置要清除的背景颜色不起作用。

  2. 我覆盖pointInside:withEvent:

    - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
        return point.y >= 0 && [super pointInside:point withEvent:event];
    }
    
  3. 请注意,您在此处不关心contentInset。表格视图的contentOffset.y(与其bounds.origin.y相同)在显示其顶级内容插入时设置为负数。当项目0的顶部位于表格视图的顶部边缘时,它被设置为0,而当项目位于屏幕的下边缘时则不是这样。

    您可能想要的另一件事是防止表格在屏幕上停止一半。如果用户在屏幕中间向上拖动项目0,您希望表格滚动,因此项目0一直在屏幕顶部(如果有足够的项目),并且如果用户将项目0拖到屏幕的中间,你希望表格滚动,所以只显示项目0。

    我通过使我的视图控制器充当表视图的委托并实现此委托方法,继承自UIScrollViewDelegate

    - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
        CGFloat yMin = -self.tableView.contentInset.top;
        CGFloat yMax = MIN(0, self.tableView.contentSize.height - self.tableView.bounds.size.height);
        if (targetContentOffset->y < yMax) {
            if (velocity.y < 0) {
                targetContentOffset->y = yMin;
            } else {
                targetContentOffset->y = yMax;
            }
        }
    }
    

    该方法经过精心编写,因此适用于表格太短而无法垂直填充屏幕,以及适用于垂直填充屏幕的表格。

    我已在此处上传了我的测试项目:https://github.com/mayoff/tableView-over-mapview

    并排表的更新

    我认为并排表不会成为一个好的用户界面。我认为这会令人困惑。但这就是你如何做到的。

    视图层次结构如下所示:

    • 根视图
      • MKMapView
      • MyScrollView
        • ScrollContentView
            第一张表
          • MyTableView
          • 第二张表
          • MyTableView
          • MyTableView for third table

    地图视图和滚动视图具有相同的框架。滚动视图处理横向滚动,每个表视图可以垂直独立滚动。

    由于滚动视图应仅捕获落在其中一个表视图中的触摸,因此需要一个自定义hitTest:withEvent:,以便在任何表视图之外返回nil

    @implementation MyScrollView
    
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
        UIView *hitView = [super hitTest:point withEvent:event];
        return hitView == self ? nil : hitView;
    }
    
    @end
    

    但这实际上并不能完成这项工作,因为(在我的实现中)滚动视图只有一个大的子视图ScrollContentView。所以我们需要在ScrollContentView中执行相同的操作:

    @implementation ScrollContentView
    
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
        UIView *hitView = [super hitTest:point withEvent:event];
        return hitView == self ? nil : hitView;
    }
    

    如果它们落在表格之外,那就足以将触摸传递到地图视图。

    我还使用ScrollContentView来布置表格并设置滚动视图的内容大小:

    - (void)layoutSubviews {
        [super layoutSubviews];
    
        // Layout of subviews horizontally:
        // [gutter/2][gutter][subview][gutter][subview][gutter][subview][gutter][gutter/2]
        // where 3 * gutter + subview = width of superview
    
        CGSize superSize = self.superview.bounds.size;
        CGFloat x = kGutterWidth * 3 / 2;
        CGFloat subWidth = superSize.width - kGutterWidth * 3;
    
        for (UITableView *subview in self.subviews) {
            subview.frame = CGRectMake(x, 0, subWidth, superSize.height);
            x += subWidth + kGutterWidth;
    
            CGFloat topInset = superSize.height - subview.rowHeight;
            subview.contentInset = (UIEdgeInsets){ .top = topInset };
            subview.contentOffset = CGPointMake(0, -topInset);
        }
    
        x += kGutterWidth / 2;
        self.frame = CGRectMake(0, 0, x, superSize.height);
        ((UIScrollView *)self.superview).contentSize = self.bounds.size;
    
        _pageWidth = subWidth + kGutterWidth;
    }
    

    我还使我的视图控制器成为滚动视图的委托,并实现了一个委托方法来强制滚动视图停止在“页面”(表)边界上:

    - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
        CGFloat pageWidth = contentView.pageWidth;
    
        // Force scroll view to stop on a page boundary.
        CGFloat pageNumber = targetContentOffset->x / pageWidth;
        if (velocity.x < 0) {
            pageNumber = floor(pageNumber);
        } else {
            pageNumber = ceil(pageNumber);
        }
        pageNumber = MAX(0, MIN(pageNumber, contentView.subviews.count - 1));
        targetContentOffset->x = pageNumber * pageWidth;
    }
    

    结果:

    multiple tables side-by-side

    我已使用此版本更新git repository

答案 1 :(得分:2)

你应该能够通过将表格视图的顶部contentInset设置为高位(如评论中建议的sha),然后将UITableView作为子类,以便覆盖{{1} }。使用它和当前-pointInside:withEvent:,您可以确定传入事件是否在您想要滚动的区域内,并相应地返回YES或NO;如果您返回NO,则触摸应按预期落入地图视图。

答案 2 :(得分:1)

为什么不完全改变它。你说你有一张地图&#34;&#34; tableview。因此,当向上滚动时,地图将被表格视图隐藏。我猜你再次向下滚动时会显示地图吗?

您应该可以使用UITableView标头执行此操作。节标题或表视图标题。滚动时它们的行为略有不同。

我也许这样做......

在桌面上使用table view header。在此标题中,您可以放置​​地图视图。

默认情况下,这将固定在表格的顶部,因此如果向上滚动表格,地图将随之滑出屏幕顶部。

但是,如果您然后截取滚动视图委托方法- (void)scrollViewDidScroll:(UIScrollView *)scrollView;,那么您可以计算出表格是否向上滚动并偏移地图视图以使其保持原样。

即。如果表格滚动到(0,10)然后将地图偏移到(0,-10),那么看起来它没有被移动。

这将为您提供tableview的滚动和输出功能,并将地图保持在视图中并响应触摸。