【问题标题】:Swipe UITableView onto screen, keep swiping?将 UITableView 滑动到屏幕上,继续滑动?
【发布时间】:2014-10-18 16:11:29
【问题描述】:

我想要一个在屏幕外开始并可以在屏幕上滚动、到达顶部并继续滚动的表格视图。我在下面对所需的交互进行了可视化。

我尝试了两件事,但都没有完全符合我的需要。

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

我尝试的第二件事是将滚动视图的内容大小设置为表格视图的高度。这让 tableview 滚动,但我似乎只能在标记为“List Item 1”的初始小矩形中接收触摸。随着 tableview 滚动,我不能再抓住中间滚动它了。

建立这种互动的最佳方式是什么? 编辑:地图围绕此底部视图向左、向右和大部分位于顶部。拉起底视图时,地图左右可见。

1.)

2.)

3.) (这会一直滚动到与列表中一样多的项目。)

【问题讨论】:

  • 为什么不把 contentInset 改成顶部的大东西(屏幕大小)?这样即使您的 tableView 将占据整个屏幕 - 列表项也只会从最底部开始。
  • @sha 不会阻止触摸滚动视图后面的东西吗?当列表向上移动和关闭时,未显示的视图需要与平移/缩放/点击交互。
  • 可能。您可能需要做一些特殊的事情才能将手势向下传递到下面的滚动视图。但是,如果您需要在用户向上滚动 tableview 时更新某些内容 - 您甚至不必这样做 - 只需正确配置和更改背景图像。
  • 列表可以中途停止,背后的东西是需要完全交互的地图。

标签: ios objective-c uitableview uiscrollview


【解决方案1】:

我猜你想要这样的东西:

或者这个:

我在地图视图上布置了表格视图。我这样设置表格视图的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];
    }
    

请注意,您在这里并不关心contentInset。表视图的contentOffset.y(与bounds.origin.y 相同)在其顶部内容插入显示时设置为负数。当 item 0 的顶部位于 table view 的顶部边缘时,它被设置为 0,而 item 位于屏幕底部边缘时则不是这种情况。

您可能想要的另一件事是防止表格停在屏幕上的一半。如果用户将项目 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 第三张桌子

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

由于滚动视图应该只捕获落在其中一个表视图中的触摸,因此它需要一个自定义的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;
}

结果:

我已经用这个版本更新了git repository

【讨论】:

  • 这是一个地狱般的答案。有机会我会试试这个。喜欢这些图片。
  • 我已经更新了我的答案,以避免表格视图在屏幕上只有一半时停止。
  • 我遇到了最后一点麻烦。我有许多动态生成的表格视图,它们位于滚动视图中。我可以进行地图交互,也可以像您演示的那样向左和向右翻页并获得正确的滚动。我已经在 pointInside 的 tableview 子类实现中对其进行了跟踪。 point.y 总是大于 0,[super pointInside] 总是返回 false。每个 tableview 的原点 x 都会偏移一个屏幕宽度,但无论我如何摆弄这个,我都被困在如何修复 pointInside 方法上。
  • CGPoint pointInSubview = [view convertPoint:point fromView:self];这就是钱。
  • 我已经并排更新了多个表格的答案和测试项目。
【解决方案2】:

您应该能够很容易地做到这一点,方法是将表格视图的顶部 contentInset 设置为较高的值(如 cmets 中的 sha 建议),然后将 UITableView 设为子类,以便您可以覆盖 -pointInside:withEvent:。使用它和当前的contentOffset,您可以确定传入的事件是否在您想要滚动的区域内,并相应地返回 YES 或 NO;如果您返回 NO,则触摸应按预期落入地图视图。

【讨论】:

  • 我会再试一次。我没想过要继承 UITableView 的 pointInside。
【解决方案3】:

为什么不完全改变这一点。您说您在表格视图“下方”有一张地图。因此,当向上滚动时,地图将被表格视图隐藏。我想当你再次向下滚动时地图会显示出来?

您应该能够通过使用UITableView 标头来执行此操作。部分标题或表格视图标题。它们在滚动时的行为略有不同。

我可能会这样做......

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

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

但是,如果您随后拦截滚动视图委托方法- (void)scrollViewDidScroll:(UIScrollView *)scrollView;,那么您可以确定表格是否正在向上滚动并偏移地图视图以使其保持原位。

即如果表格滚动到 (0, 10),则将地图偏移到 (0, -10),因此看起来它没有移动。

这将为您提供表格视图的滚动进出功能,并使地图保持在视图中并响应触摸。

【讨论】:

  • 我在图片中没有说清楚的是,在拉起之前和拉起时,地图实际上出现在最底部单元格的左右两侧。我会更新问题。
  • @StefanKendall 你仍然可以做同样的事情。仍然会以同样的方式工作(如果我理解你的意思)。
  • @StefanKendall 也许你想要实现的一些更详细的屏幕截图会有所帮助?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多