Objective c 带UIButtons的UIScrollview-如何重新创建跳板?
我正在尝试在我的应用程序中创建一个类似跳板的界面。我正在尝试使用添加到UIScrollView的UIButtons。我遇到的问题是按钮没有向UIScrollView传递任何触摸信息-如果我尝试轻弹/滑动并碰巧按下按钮,它不会注册为UIScrollView,但是如果我轻弹按钮之间的空间,它会工作。如果我触摸按钮,它们会发出咔嗒声 是否有强制按钮将触摸事件发送到其父级(superview)的属性或设置?在添加到UIScrollView之前,是否需要将按钮添加到其他内容 这是我的密码:Objective c 带UIButtons的UIScrollview-如何重新创建跳板?,objective-c,uiscrollview,uibutton,programmatically-created,Objective C,Uiscrollview,Uibutton,Programmatically Created,我正在尝试在我的应用程序中创建一个类似跳板的界面。我正在尝试使用添加到UIScrollView的UIButtons。我遇到的问题是按钮没有向UIScrollView传递任何触摸信息-如果我尝试轻弹/滑动并碰巧按下按钮,它不会注册为UIScrollView,但是如果我轻弹按钮之间的空间,它会工作。如果我触摸按钮,它们会发出咔嗒声 是否有强制按钮将触摸事件发送到其父级(superview)的属性或设置?在添加到UIScrollView之前,是否需要将按钮添加到其他内容 这是我的密码: //init
//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本身处理很多事件。您需要手动处理UIScrollView内按钮的触控DIDEND和hit测试。为了让
UIScrollView
确定通过其内容视图的点击与变成滑动或挤压的触控之间的差异,它需要延迟触摸,并查看您的手指是否在延迟期间移动。在上面的示例中,通过将delaysContentTouches
设置为NO
,可以防止这种情况发生。因此,滚动视图总是将触摸传递给按钮,而不是在用户执行滑动手势时取消触摸。尝试将delaysContentTouches
设置为YES
从结构上讲,最好将滚动视图中要承载的所有视图添加到公共内容视图中,并仅将该视图用作滚动视图的子视图。另一种方法是:
1。用简单的自定义UIView替换de按钮
2。在init方法上设置标志“userinteractionenable=yes;”
3。在视图中,覆盖UIResponder方法“touchesend”,您可以像按钮一样触发所需的操作。根据我的经验,第一个答案,即简单地将
延迟内容切换设置为是
,不会改变与问题相关的任何内容。这些按钮仍不会将跟踪结果传送到滚动视图。第三个答案既简单又实用。谢谢sieroaoj
但是,要使第三个答案起作用,您还需要将delaysContentTouches
设置为YES
。否则,也将调用方法touchesend
在视图中进行跟踪。因此,我可以通过以下方式解决问题:
用简单的自定义UIView替换de按钮
在init方法上放置标志“userinteractionenable=yes;”
在视图中,在此处覆盖UIResponder方法“touchesEnded”
你可以触发你想要的动作
四,。将delaysContentTouches
设置为YES
确定以下是您的答案:
子类UIButton。(注意:在每次覆盖开始时调用[super…]
- 添加属性。类型为BOOL的属性之一
(称为enableToRestore)
- 添加属性。CGPoint类型之一
(称为startTouchPosition)
- 从笔尖和
initWithFrame,设置
启用存储到已启用的
财产)
- 覆盖“触摸开始:withEvent:”
存储触摸的开始
位置
- 覆盖“touchesMoved:withEvent:”至
检查是否有水平面
运动
- 如果是,则将启用设置为否,然后
选择为否
示例代码:
- (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:
- 在类别中:
编辑
注:我从未得到过答案3。
同样,设置setDelaysContentTouches:NO(在视图控制器或某处设置)可在回答4时获得最佳结果。这可提供对按钮的快速响应。设置setDelaysContentTouches:YES会产生严重影响(150毫秒)在按钮的响应时间上,使轻巧、快速的触摸变得不可能。我有一个类似的情况,在UIScrollView上有许多按钮,我想滚动这些按钮。开始时,我对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
对我有效的解决方案包括:
将UIScrollView
中的canCancelContentTouches
设置为YES
扩展UIScrollView
以覆盖touchesShouldCancelInContentView:(UIView*)视图
以在view
是UIButton
时返回YES
根据文档touchesshouldcanceincontview
返回“YES
取消要查看的进一步触摸消息,NO
让视图继续接收这些消息。如果视图不是UIControl
对象,默认返回值为YES
,否则返回NO
”
由于ui按钮
是一个UIControl
扩展是必要的,以使CanCancancelContentTouches
生效,从而启用滚动。执行延迟ContentTouches的一个可能问题是,它会在按钮高亮显示之前添加延迟。下面的Roman K回答将允许您没有延迟,但在按下按钮后仍能滚动。结构建议很棒,但我想知道原因。谢谢。非常感谢!澄清一下,这在delaysContentTouches=NO时最有效。这就是方法!(至少对于iOS 4+)我发现这样的覆盖最通用:-(BOOL)touchesShouldCancelInContentView:(UIView*)视图{return![view isKindOfClass:[UISlider class]];}
它仍然不适用于
-(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];
}
}
}
@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