UIBcrollview与UIButtons - 如何重新创建跳板?

时间:2009-03-16 13:33:29

标签: objective-c uiscrollview uibutton programmatically-created

我正在尝试在我的应用中创建类似跳板的界面。我正在尝试将UIButtons添加到UIScrollView中。我正在运行的问题是按钮没有通过任何触摸到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];

7 个答案:

答案 0 :(得分:44)

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

  1. canCancelContentTouches中的UIScrollView设置为YES
  2. UIScrollViewtouchesShouldCancelInContentView:(UIView *)view时,将YES扩展为覆盖view以返回UIButton
  3. 根据文档touchesShouldCancelInContentView返回“YES取消进一步触摸要查看的消息,NO让视图继续接收这些消息。默认返回值为YES如果view不是UIControl对象;否则返回NO。“

    由于UIButtonUIControl,因此必须使用canCancelContentTouches生效才能生成滚动。

答案 1 :(得分:28)

为了让UIScrollView确定通过其内容视图的点击与变成滑动或捏合的点击之间的差异,它需要延迟触摸并查看您的手指在那段延迟期间搬家了。通过在上面的示例中将delaysContentTouches设置为NO,您可以防止这种情况发生。因此,滚动视图总是将触摸传递给按钮,而不是在事实证明用户正在执行滑动手势时取消它。尝试将delaysContentTouches设置为YES

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

答案 2 :(得分:5)

我有类似的情况,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

答案 3 :(得分:1)

UIScrollView本身处理很多事件。您需要手动处理touchesDidEnd并对UIScrollView内的按钮进行测试。

答案 4 :(得分:1)

好的,这是你的答案:

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

  • 添加媒体资源。 BOOL类型之一 (称为enableToRestore)
  • 添加媒体资源。 CGPoint类型之一 (称为startTouchPosition)
  • 在awakeFromNib中 initWithFrame,设置 enableToRestore到isEnabled 属性)
  • 覆盖“touchesBegan:withEvent:” 存储触摸的开始 位置。
  • 覆盖“touchesMoved:withEvent:” 检查是否有水平 运动。
  • 如果是,则将启用设置为NO和 选为NO。

示例代码:

- (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];
        }
    }
}

EDIT 注意:我从来没有得到答案3的工作。 同样:setDelaysContentTouches:NO(在视图控制器或某个地方设置)将在答案4上设置为最佳结果。这样可以非常快速地响应按钮。设置setDelaysContentTouches:YES会对按钮的响应时间造成严重影响(150毫秒),并且无法轻松快速触摸。

答案 5 :(得分:0)

另一种方式是:1。用简单的自定义UIView替换de按钮。把标志“userInterationEnable = yes;”在初始化方法中3.在视图中覆盖UIResponder方法“touchesEnded”,您可以像按钮一样触发所需的操作。

答案 6 :(得分:0)

根据我的经验,第一个答案,即简单地将delaysContentTouches设置为YES,不会改变与问题有关的任何内容。按钮仍然不会将滚动视图提供跟踪结果。第三个答案既简单又实用。谢谢sieroaoj!

但是,对于第三个工作答案,您还需要将delaysContentTouches设置为YES。否则,还将调用方法touchesEnded以在视图中进行跟踪。因此,我可以通过以下方式解决问题:

  
      
  1. 通过简单的自定义UIView替换de按钮
  2.   
  3. 放置标志“userInterationEnable = yes;”关于init方法
  4.   
  5. 在视图中覆盖UIResponder方法“touchesEnded”   你可以触发你的行动
  6.   

四。将delaysContentTouches设置为YES