UIScrollview 与 UIButtons - 如何重新创建跳板?
-
19-08-2019 - |
题
我正在尝试在我的应用程序中创建一个类似跳板的界面。我正在尝试使用添加到 UIScrollView 的 UIButtons。我遇到的问题是按钮没有将任何触摸传递给 UIScrollView - 如果我尝试轻弹/滑动并碰巧按下按钮,它不会注册 UIScrollView,但是如果我轻弹之间的空格按钮它就会起作用。如果我触摸按钮,它们就会点击/工作。
是否有属性或设置强制按钮将触摸事件发送到其父级(超级视图)?在添加 UIScrollView 之前是否需要将按钮添加到其他内容?
这是我的代码:
//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
,您要阻止这种情况的发生。因此,滚动视图总是通过触摸到按钮,而不是将其结果是用户正在执行滑动手势时取消它。尝试设置到delaysContentTouches
YES
。
这也可能是一个好主意,在结构上,添加所有的意见,你的滚动视图被托管到一个共同的内容视图,并仅使用一个视图作为滚动视图的子视图。
其他提示
对我有用的解决方案包括:
- 环境
canCancelContentTouches
在UIScrollView
到YES
. - 延伸
UIScrollView
覆盖touchesShouldCancelInContentView:(UIView *)view
回来YES
什么时候view
是一个UIButton
.
根据文件 touchesShouldCancelInContentView
返回“YES
取消进一步触摸消息以查看, NO
以便查看继续接收这些消息。默认返回值为 YES
如果视图不是 UIControl
目的;否则,它返回 NO
."
自从 UIButton
是一个 UIControl
需要扩展才能获得 canCancelContentTouches
使滚动生效。
我有许多上一个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
@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
的内部按钮好的,这是你的答案:
UIButton 的子类。(笔记:在每次覆盖开始时调用 [super ....]。
- 添加属性。Bool类型之一(称为EnableTorestore)
- 添加属性。CGPoint类型之一(称为startTouchPosition)
- 在Awakefromnib和InitwithFrame中,将EnableTorestore设置为IseNabled属性)
- 覆盖“touchesBegan:withvent:“存储触摸位置的开始。
- 覆盖“touchesMoved:withvent:“检查是否有水平运动。
- 如果是,请设置为否,并选择为否。
示例代码:
- (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:与事件:”
- 在覆盖中,重置所有子视图(及其子视图)启用标志。
- 笔记:使用 Category 并将方法添加到 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 的最佳结果。这提供了对按钮的非常快速的响应。设置 setDelaysContentTouches:YES 会对按钮的响应时间产生严重影响(150 毫秒),并且无法实现轻快的触摸。
另一种方法是:结果1。通过一个简单的自定义的UIView替补德按钮点击2。把标志 “userInterationEnable = YES”;上的init方法,点击3.在视图重写UIResponder方法“touchesEnded”在这里可以触发你需要像按钮的动作。
根据我的经验,第一个答案,即简单地设置 delaysContentTouches
到 YES
, ,不会改变问题的任何内容。这些按钮仍然不会将跟踪结果传递到滚动视图。第三个答案既简单又非常有用。谢谢谢罗奥!
但是,要使第三个答案起作用,您还需要 delaysContentTouches
设置 YES
. 。否则方法 touchesEnded
也将被要求在视图内进行跟踪。因此我可以通过以下方式解决问题:
- 用简单的自定义 UIView 替换按钮
- 在初始化方法中加入 "userInterationEnable = yes; "标记
- 在视图中覆盖 UIResponder 方法 "touchesEnded 您可以触发您
第四。放 delaysContentTouches
到 YES