我正在尝试在我的应用程序中创建一个类似跳板的界面。我正在尝试使用添加到 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确定通过其内容视图(一个或多个)和触摸其变成滑动或捏通过点击之间的差,它需要以延迟所述触摸,看看是否您的手指已经期间移动延迟。通过在上面的例子中设置delaysContentTouchesNO,您要阻止这种情况的发生。因此,滚动视图总是通过触摸到按钮,而不是将其结果是用户正在执行滑动手势时取消它。尝试设置到delaysContentTouches YES

这也可能是一个好主意,在结构上,添加所有的意见,你的滚动视图被托管到一个共同的内容视图,并仅使用一个视图作为滚动视图的子视图。

其他提示

对我有用的解决方案包括:

  1. 环境 canCancelContentTouchesUIScrollViewYES.
  2. 延伸 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”在这里可以触发你需要像按钮的动作。

根据我的经验,第一个答案,即简单地设置 delaysContentTouchesYES, ,不会改变问题的任何内容。这些按钮仍然不会将跟踪结果传递到滚动视图。第三个答案既简单又非常有用。谢谢谢罗奥!

但是,要使第三个答案起作用,您还需要 delaysContentTouches 设置 YES. 。否则方法 touchesEnded 也将被要求在视图内进行跟踪。因此我可以通过以下方式解决问题:

  1. 用简单的自定义 UIView 替换按钮
  2. 在初始化方法中加入 "userInterationEnable = yes; "标记
  3. 在视图中覆盖 UIResponder 方法 "touchesEnded 您可以触发您

第四。放 delaysContentTouchesYES

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top