UIScrollview与UIButtons – 如何重新创build跳板?

我试图在我的应用程序中创build一个类似跳板的界面。 我试图使用UIButtons添加到UIScrollView。 我运行的问题是与button没有通过任何接触的UIScrollView – 如果我试图轻弹/幻灯片,碰巧按下的button,它不注册的UIScrollView,但如果我轻弹之间的空间button它将工作。 如果我触摸它们,button会点击/工作。

是否有一个属性或设置强制button将触摸事件发送到其父(superview)? 在添加UIScrollView之前,button是否需要添加到其他东西?

这是我的代码:

//init scrolling area UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 480, 480)]; scrollView.contentSize = CGSizeMake(480, 1000); scrollView.bounces = NO; scrollView.delaysContentTouches = NO; //create background image UIImageView *rowsBackground = [[UIImageView alloc] initWithImage:[self scaleAndRotateImage:[UIImage imageNamed:@"mylongbackground.png"]]]; rowsBackground.userInteractionEnabled = YES; //create button UIButton *btn = [[UIButton buttonWithType:UIButtonTypeCustom] retain]; btn.frame = CGRectMake(100, 850, 150, 150); btn.bounds = CGRectMake(0, 0, 150.0, 150.0); [btn setImage:[self scaleAndRotateImage:[UIImage imageNamed:@"basicbutton.png"]] forState:UIControlStateNormal]; [btn addTarget:self action:@selector(buttonClick) forControlEvents:UIControlEventTouchUpInside]; //add "stuff" to scrolling area [scrollView addSubview:rowsBackground]; [scrollView addSubview:btn]; //add scrolling area to cocos2d //this is just a UIWindow [[[Director sharedDirector] openGLView] addSubview:scrollView]; //mem-mgmt [rowsBackground release]; [btn release]; [scrollView release]; 

为了使UIScrollView能够确定通过它的内容视图的点击与触摸变成轻扫或捏合之间的差异,它需要延迟触摸并且看看在这个延迟期间你的手指是否移动了。 通过在上面的示例delaysContentTouches设置为NO ,可以防止发生这种情况。 因此,滚动视图总是将触摸传递给button,而不是在用户正在执行轻扫手势时取消该button。 尝试将delaysContentTouches设置为YES

在结构上,将所有要在滚动视图中托pipe的视图添加到公共内容视图,并仅将该视图用作滚动视图的子视图也可能是一个好主意。

为我工作的解决scheme包括:

  1. UIScrollView canCancelContentTouches设置为YES
  2. 扩展UIScrollView覆盖touchesShouldCancelInContentView:(UIView *)view返回YES时, view是一个UIButton

根据文档touchesShouldCancelInContentView返回“ YES来取消进一步的触摸消息来查看, NO有视图继续接收这些消息。如果view不是一个UIControl对象,默认返回值是YES ;否则返回NO

由于UIButton是一个UIControl的扩展是必要的,让canCancelContentTouches生效,使滚动。

我有一个类似的情况,在UIScrollView上的一些button,我想滚动这些button。 在开始的时候,我将UIScrollView和UIButton都分类了。 不过,我注意到我的子类UIScrollView没有收到touchesEnded事件,所以我改为只有子类UIButton。

 @interface MyPhotoButton : UIButton { } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event; @end 
 @implementation MyPhotoButton - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesMoved:touches withEvent:event]; [self setEnabled:NO]; [self setSelected:NO]; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesEnded:touches withEvent:event]; [self setEnabled:YES]; } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesCancelled:touches withEvent:event]; [self setEnabled:YES]; } @end 

UIScrollView本身处理很多事件。 您需要处理touchesDidEnd并手动按UIScrollView中的button。

好的,这里是你的答案:

子类UIButton。 (注意:在每个覆盖开始时调用[super ….]。

  • 添加一个属性。 BOOLtypes(称为enableToRestore)
  • 添加一个属性。 一个CGPointtypes(称为startTouchPosition)
  • 在awakeFromNib和initWithFrame中,将enableToRestore设置为isEnabled属性)
  • 覆盖“touchesBegan:withEvent:”来存储触摸位置的开始。
  • 覆盖“touchesMoved:withEvent:”来检查是否存在水平移动。
  • 如果是,则将启用设置为否,并将其select为否。

示例代码:

 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; [super touchesBegan:touches withEvent:event]; [self setStartTouchPosition:[touch locationInView:self]]; } // // Helper Function // - (BOOL)isTouchMovingHorizontally:(UITouch *)touch { CGPoint currentTouchPosition = [touch locationInView:self]; BOOL rValue = NO; if (fabsf([self startTouchPosition].x - currentTouchPosition.x) >= 2.0) { rValue = YES; } return (rValue); } // // This is called when the finger is moved. If the result is a left or right // movement, the button will disable resulting in the UIScrollView being the // next responder. The parrent ScrollView will then re-enable the button // when the finger event is ended of cancelled. // - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesMoved:touches withEvent:event]; if ([self isTouchMovingHorizontally:[touches anyObject]]) { [self setEnabled:NO]; [self setSelected:NO]; } } 

这将激活UIScrollView。

子类UIScrollView。 (注意:在每个覆盖开始时调用[super ….]。

  • 覆盖“touchesEnded:withEvent:”和“touchesCancelled:withEvent:”
  • 在覆盖,重置所有子视图(及其子视图)启用标志。
  • 注意:使用类别并将该方法添加到UIView:

 - (void) restoreAllEnables { NSArray *views = [self subviews]; for (UIView *aView in views) { if ([aView respondsToSelector:@selector(restoreEnable)]) { [aView restoreEnable]; } } } - (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesEnded:touches withEvent:event]; [self restoreAllEnables]; } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesEnded:touches withEvent:event]; [self restoreAllEnables]; } 
  • 在类别:

 -(void) restoreEnable { NSArray *views = [self subviews]; if ([self respondsToSelector:@selector(enableToRestore)]) { [self setEnabled:[self enableToRestore]]; } for (UIView *aView in views) { if ([aView respondsToSelector:@selector(restoreEnable)]) { [aView restoreEnable]; } } } 

编辑注:我从来没有得到答案3的工作。 同样地:setDelaysContentTouches:NO(在视图控制器或某个地方设置)将被设置为答案4的最佳结果。这提供了对button的快速响应。 设置setDelaysContentTouches:YES对button的响应时间产生严重的影响(150ms),使得光线不能快速触摸。

另一种方法是:
1.用一个简单的自定义UIView代替debutton
2.将标志“userInterationEnable = yes;” 在init方法上
3.在视图中,覆盖UIResponder方法“touchesEnded”,您可以触发您需要的操作,如button。

根据我的经验,第一个答案,即简单地设置delaysContentTouchesYES ,不会改变任何问题。 这些button仍然不会将跟踪结果传递给滚动视图。 第三个答案既简单又实用。 谢谢sieroaoj!

但是,对于第三个工作答案,您还需要将delaysContentTouches设置为YES 。 否则touchesEnded的方法也将在视图内被调用。 所以我可以通过以下方式解决问题:

  1. 用一个简单的自定义UIView代替debutton
  2. 把标志“userInterationEnable = yes;” 在init方法上
  3. 在视图覆盖UIResponder方法“touchesEnded”在这里你可以触发你的行动

第四。 将delaysContentTouches设置为YES