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

Ste*_*all 2 objective-c uitableview uiscrollview ios

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

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

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

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

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

1.)
1

2.)
2

3.)(这将继续滚动列表中的多个项目.)
3

rob*_*off 18

我想你想要这样的东西:

小清单

或这个:

大名单

我在地图视图上显示了我的表格视图.我设置了表格视图contentInset,contentOffset如下所示:

- (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);
}
Run Code Online (Sandbox Code Playgroud)

请注意,虽然默认行高为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];
    }
    
    Run Code Online (Sandbox Code Playgroud)

请注意,你不在乎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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

更新并排表

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

视图层次结构如下所示:

  • 根视图
    • MKMapView
    • MyScrollView
      • ScrollContentView
        • MyTableView 对于第一张桌子
        • MyTableView 对于第二张桌子
        • MyTableView 为第三个表
        • 等等

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

由于滚动视图应仅捕获落在其中一个表视图中的触摸,因此它需要一个自定义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
Run Code Online (Sandbox Code Playgroud)

但这实际上并不能完成这项工作,因为(在我的实现中)滚动视图只有一个大的子视图,即ScrollContentView.所以我们需要做同样的事情ScrollContentView:

@implementation ScrollContentView

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    UIView *hitView = [super hitTest:point withEvent:event];
    return hitView == self ? nil : hitView;
}
Run Code Online (Sandbox Code Playgroud)

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

我还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;
}
Run Code Online (Sandbox Code Playgroud)

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

- (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;
}
Run Code Online (Sandbox Code Playgroud)

结果:

多个表并排

我用这个版本更新了git存储库.

  • 这是一个helluvan的答案.当我有机会的时候我会试试这个.喜欢这些图片. (2认同)