UIScrollView内的UITableView在滚动后没有收到第一次点击

Ang*_*qui 31 objective-c uitableview uiscrollview ios

简要

我在UITableView内心问题UIScrollView.当我滚动外部时scrollView,第一次触摸时table不会收到willSelect/didSelect事件,但第二次触摸时不会收到事件.更奇怪的是,细胞本身会得到触摸和突出显示的状态,即使delegate没有.

详细解释

我的视图层次结构

UIView
  - UIScrollView  (outerscroll)
      - Some other views and buttons
      - UITableView (tableView)
Run Code Online (Sandbox Code Playgroud)

在滚动视图中,我有一些额外的视图可以动态扩展/关闭.表格视图需要与视图中的其他一些元素一起"固定"在顶部,这就是我创建此布局的原因,这使我可以通过使用转换以类似于Apple推荐的方式轻松移动元素.滚动发生了.

当outerscroll像这样移动时,表视图将使用转换效果进行转换:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (scrollView == self.outerScrollView) {

        CGFloat tableOffset = scrollView.contentOffset.y - self.fixedHeaderFrame.origin.y;
        if (tableOffset > 0) {
            self.tableView.contentOffset = CGPointMake(0, tableOffset);
            self.tableView.transform = CGAffineTransformMakeTranslation(0, tableOffset);
        }
        else {
            self.tableView.contentOffset = CGPointMake(0, 0);
            self.tableView.transform = CGAffineTransformIdentity;
        }

        // Other similar transformations are done here, but not involving the table

}
Run Code Online (Sandbox Code Playgroud)

在我的单元格中,如果我实现这些方法:

- (void)setSelected:(BOOL)selected {
    [super setSelected:selected];
    if (selected) {
        NSLog(@"selected");
    }
}

- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{
    [super setHighlighted:highlighted animated:animated];
    if (highlighted) {
        NSLog(@"highlighted");
    }
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesBegan:touches withEvent:event];
    NSLog(@"touchesBegan");
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesEnded:touches withEvent:event];
    NSLog(@"touchesEnded");
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesCancelled:touches withEvent:event];
    NSLog(@"touchesCancelled");
}
Run Code Online (Sandbox Code Playgroud)

失败时,Y可以看到此输出(第一次点击):

2014-02-10 13:04:40.940 MyOrderApp[5588:70b] highlighted 
2014-02-10 13:04:40.940 MyOrderApp[5588:70b] touchesBegan 
2014-02-10 13:04:40.978 MyOrderApp[5588:70b] touchesEnded
Run Code Online (Sandbox Code Playgroud)

有效时(第二次点击):

2014-02-10 13:05:30.359 MyOrderApp[5588:70b] highlighted 
2014-02-10 13:05:30.360 MyOrderApp[5588:70b] touchesBegan 
2014-02-10 13:05:30.487 MyOrderApp[5588:70b] touchesEnded 
2014-02-10 13:05:30.498 MyOrderApp[5588:70b] expanded
Run Code Online (Sandbox Code Playgroud)

在第一次和第二次点击之间没有进行其他帧改变,动画或任何其他视图交互.此外,只有在滚动大量时才会出现错误,但只有几个像素的滚动,一切都按预期工作.

我也尝试改变一些属性,但没有运气.我做过的一些事情:

  • userInteractionEnabled从滚动和表格以外的视图中删除
  • setNeedsLayout在桌面上添加一个调用,在scrollViewDidScroll发生时滚动和主视图.
  • 从表中删除转换(仍然发生)

我所看到的有关嵌入的意外行为的一些评论UITableViews里面UIScrollViews,但我看不到苹果的官方文档中这样的警告,所以我期待它的工作.

该应用程序仅限iOS7 +.

问题

有没有人遇到类似的问题?为什么这样,如何解决?我认为我能够拦截单元格上的点击手势并使用自定义委托或类似方式传递它,但我希望表格能够接收正确的事件,因此我UITableViewDelegate按预期接收它.

更新

  • 我尝试按照评论中的建议禁用单元格重用,但它仍然以相同的方式发生.

Rém*_*rin 23

Apple文档中,你不应该嵌入一个UITableView内部UIScrollView.

重要提示:您不应在UIScrollView对象中嵌入UIWebView或UITableView对象.如果这样做,可能会导致意外行为,因为两个对象的触摸事件可能混淆和错误处理.

你的问题与你的问题有关UIScrollView.

但是如果只是在需要时隐藏tableview(这是我的情况),你可以移动UITableView它的superview.

我在这里写了一个小例子:https://github.com/rvirin/SoundCloud/


小智 20

将内部UITableView的scrollEnabled属性设置为YES.这让内部UITableView知道正确处理滚动相关的触摸UIScrollView.

  • 这就是答案.是的,不支持在scrollView中嵌入tableView,但如果你从未像现在这样遵守规则(如我),那么就是如何解决上面提到的问题!我还要补充一点,任何嵌入式tableView都应该将`bounces`设置为`NO`以避免可能奇怪的滚动行为. (2认同)

Ore*_*ren 14

我遇到了同样的问题并找到了解决方案!

您需要在delaysTouchesBegan滚动视图上将其设置为true,以便scrollview将其失败的滚动手势(即点按)发送给其子项.

var delaysTouchesBegan: Bool- 确定接收器是否将开始阶段中的触摸发送到其视图的布尔值.

当属性的值为YES时,窗口会暂停UITouchPhaseBegan阶段中触摸对象到视图的传递.如果手势识别器随后识别其手势,则丢弃这些触摸对象.但是,如果手势识别器无法识别其手势,则窗口会以touchesBegan:withEvent:消息(以及可能的后续touchesMoved:withEvent:消息将这些对象传递给视图,以通知其触摸的当前位置) .

https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIGestureRecognizer_Class/index.html#//apple_ref/occ/instp/UIGestureRecognizer/delaysTouchesBegan

但是有一个问题......如果你直接在scrollview上做它就行不通!

// Does NOT work
self.myScrollview.delaysTouchesBegan = true
Run Code Online (Sandbox Code Playgroud)

显然这是一个iOS错误,设置此属性不起作用(谢谢苹果).但是有一个简单的解决方法:直接在scrollview的平移手势上设置属性.果然,这对我很有用:

// This works!!
self.myScrollview.panGestureRecognizer.delaysTouchesBegan = true
Run Code Online (Sandbox Code Playgroud)


小智 1

我建议寻找一些选项,例如当您实际滚动外部滚动视图时不让单元格处于突出显示状态,这非常容易处理,并且是推荐的方式。您只需通过以下方法获取布尔值并切换它即可做到这一点

- (void)scrollViewDidScroll:(UIScrollView *)scrollView 
Run Code Online (Sandbox Code Playgroud)