裁剪边界之外的 UIScrollview 子视图未接收到触摸

Posted

技术标签:

【中文标题】裁剪边界之外的 UIScrollview 子视图未接收到触摸【英文标题】:UIScrollview subviews outside of clipping bounds not receiving touches 【发布时间】:2010-12-13 22:17:49 【问题描述】:

我有一个 UIScrollView,我已将其设置为一次滑动一列(每页两列) - 通过将框架设置为视图实际宽度的一半,将 clipToBounds 设置为 NO 并使用 hitTest 声明外部区域属于 UIScrollView 的框架(参见下面的示例)。

这很好用,但我现在的问题是 UIScrollView 的子视图没有收到任何触摸事件 - 只有主 UIScrollView 有。

在以下示例中,如果包含hitTest 代码,则滚动视图正确滚动,一次分页一列,并且可以看到其所有内容 - 但内部滚动视图不接收触摸事件。

如果我删除hitTest 代码,那么只有第一个子滚动视图会收到触摸,并且它的所有内容都可以看到 - 但主滚动视图不会在非剪切区域中获得触摸。

我该如何解决这个问题?

例子:

//=========================================
// UIScrollViewEx
// Just in order to log touches...
//=========================================

@interface UIScrollViewEx : UIScrollView  
@end

@implementation UIScrollViewEx
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
    NSLog(@"Touches Began (0x%08X)", (unsigned int)self);

@end

//=========================================
// UIViewEx
// Dummy class - sets subview as hit target
// just to demonstrate usage of non-clipped 
// content
//=========================================

@interface UIViewEx : UIView  
@end

@implementation UIViewEx
- (UIView *) hitTest:(CGPoint) point withEvent:(UIEvent *)event 
    if ([self pointInside:point withEvent:event]) 
        return [self.subviews objectAtIndex:0];
    
    return nil;

@end

//=========================================
// MainClass
// Any UIViewEx based class which returns
// the UIScrollView child on hittest
//=========================================

@implementation MyClass

- (UIColor*) randomColor

    int r = arc4random() % 100;
    int g = arc4random() % 100;
    int b = arc4random() % 100;
    return [UIColor colorWithRed:(0.01 * r) green:(0.01 * g) blue:(0.01 * b) alpha:1.0];


- (void) loadScrollviews

    // Set frame to half of actual width so that paging will swipe half a page only
    CGRect frame = CGRectMake(0, 0, self.bounds.size.width / 2, 400);

    // Main scrollview
    UIScrollView *scrollview = [[UIScrollView alloc] initWithFrame:frame];
    [scrollview setBackgroundColor:[UIColor greenColor]];
    [scrollview setPagingEnabled:YES];
    [scrollview setClipsToBounds:NO];

    // Create smaller scrollviews inside it - each one half a screen wide
    const int numItems = 5;
    for(int i = 0; i < numItems; ++i) 
        frame.origin.x = frame.size.width * i;
        UIScrollView *innerScrollview = [[UIScrollViewEx alloc] initWithFrame:frame];
        [innerScrollview setContentSize:CGSizeMake(frame.size.width, 1000)];
        [innerScrollview setBackgroundColor:[self randomColor]];
        [scrollview addSubview:innerScrollview];
        [innerScrollview release];
    

    [scrollview setContentSize:CGSizeMake(numItems * frame.size.width, frame.size.height)];

    [self addSubview:scrollview];


@end

更新 我通过执行以下操作将触摸转发到内部视图,但肯定有更好的方法吗?

- (UIView *) hitTest: (CGPoint) pt withEvent: (UIEvent *) event 
    
    if(CGRectContainsPoint(self.bounds, pt)) 
    
        UIScrollView *scrollview = [self.subviews objectAtIndex:0];
        CGPoint scrollViewpoint = [scrollview convertPoint:pt fromView:self];

        for(UIView *view in scrollview.subviews) 
            if(CGRectContainsPoint(view.frame, scrollViewpoint)) 
                return view;
            
        
        return scrollview;
     
    else 
        return [super hitTest:pt withEvent:event];
    

【问题讨论】:

我看到它与此 (***.com/questions/3735218/…) 类似,但问题仍然存在。 【参考方案1】:

这可能有效:

- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event 
    UIView* child = nil;
    if ((child = [super hitTest:point withEvent:event]) == self)
        return self.scrollView;         
    return child;

但如果子视图超出滚动视图边界,则不会触发事件并且此函数返回 self.scrollView。

【讨论】:

以上是关于裁剪边界之外的 UIScrollview 子视图未接收到触摸的主要内容,如果未能解决你的问题,请参考以下文章

如何在被父视图部分裁剪的子视图上触发 UITapGestureRecognizer?

UIScrollView 子视图在缩放下不保持正确的边界尺寸

记录 UIScrollView 的子视图会显示未添加的子视图

在视图是 UIScrollview 的子视图的 UIViewController 中未收到 NSNotification

iOS UIScrollView clipToBounds = NO 未检测到子视图

获取 UIScrollView 中可见视图之外的 UIButtons 的框架/原点