Pergunta

Eu estou tentando criar uma interface de trampolim-como dentro do meu aplicativo. Eu estou tentando usar UIButtons adicionados a um UIScrollView. O problema que eu estou correndo para é com os botões não passar qualquer toques para o UIScrollView - se eu tentar filme / slide e acontecer de imprensa sobre o botão não se inscrever para o UIScrollView, mas se eu apertar o espaço entre botões que vai funcionar. Os botões do mouse / trabalho se eu tocá-los.

Existe uma propriedade ou configuração que força o botão para enviar os eventos de toque para seu pai (superview)? Fazer os botões precisam ser adicionados para outra coisa antes de ser adicionado o UIScrollView?

Aqui está o meu código:

//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];
Foi útil?

Solução

Para UIScrollView para determinar a diferença entre um clique que passa através de seu conteúdo view (s) e um toque que se transforma em um furto ou beliscar, ele precisa atrasar o toque e veja se o seu dedo se moveu durante esse demora. Ao definir delaysContentTouches para NO no seu exemplo acima, você está impedindo que isso aconteça. Portanto, a visão de rolagem está sempre passando o toque do botão, em vez de cancelá-lo quando verifica-se que o usuário está executando um gesto de furto. Tente definir delaysContentTouches para YES.

Ele também pode ser uma boa ideia, estruturalmente, para adicionar todos os pontos de vista a ser hospedado em seu ponto de vista de rolagem para a exibição de conteúdo comum e só usar que um ponto de vista como subexibição da exibição da rolagem.

Outras dicas

solução que funcionou para mim incluído:

  1. Configuração canCancelContentTouches em UIScrollView para YES.
  2. Estendendo UIScrollView para touchesShouldCancelInContentView:(UIView *)view substituição para YES retorno quando view é um UIButton.

De acordo com a documentação touchesShouldCancelInContentView retornos "YES para cancelar mais mensagens Toque para ver, NO ter vista continuar a receber essas mensagens O valor padrão retornado é YES se a visão não é um objeto UIControl;. Caso contrário, retorna NO."

Desde UIButton é um UIControl a extensão é necessária para obter canCancelContentTouches entrem em vigor que permite a rolagem.

Eu tenho um caso semelhante que um número de botões em um UIScrollView, e eu quero rolar esses botões. No início, eu subclasse tanto UIScrollView e UIButton. No entanto, notei que meu subclasse UIScrollView não recebeu touchesEnded evento, então eu mudei a única subclasse 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 lida com um monte de si eventos. Você precisa lidar com touchesDidEnd e teste de visitas para os botões dentro do UIScrollView manualmente.

OK aqui está sua resposta:

subclasse UIButton. (NOTA:. Chamada [Super ....] no início de cada override

  • Adicione uma propriedade. Uma do tipo BOOL (Chamado enableToRestore)
  • Adicione uma propriedade. Um dos tipo CGPoint (Chamado startTouchPosition)
  • no awakeFromNib e initWithFrame, defina o enableToRestore ao isEnabled propriedade)
  • Override "touchesBegan: withEvent:" para armazenar o início do toque posição.
  • Override "touchesMoved: withEvent:" para verificar para ver se há horizontal movimento.
  • Se SIM, conjunto permitiu NO e selecionado para NO.

Exemplo de código:

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

Isso irá ativar o UIScrollView.

subclasse UIScrollView. (NOTA:. Chamada [Super ....] no início de cada override

  • Substituir ambos "touchesEnded: withEvent:" e "touchesCancelled: withEvent:"
  • Na substituição, redefinir todos os subviews (e seus subviews) habilitado bandeira.
  • NOTA: Use uma categoria e adicionar o método para 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];
}
  • Na categoria:

.

-(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 Nota: Eu nunca tive Resposta 3 a trabalho. Da mesma forma: os setDelaysContentTouches: NÃO (definidos no controlador de vista ou em algum lugar) deve ser ajustado para melhores resultados em Resposta 4. Isto fornece resposta muito rápida para os botões. Definir setDelaysContentTouches:. Puts SIM um sério impacto (150ms) no tempo de resposta para os botões e torna leve, rápido não tocando possível

Outra maneira é:
1. Substituto de botão por um simples costume UIView
2. Coloque a bandeira "userInterationEnable = yes;" no método init
3. Na vista substituir o método UIResponder "touchesEnded" aqui você pode desencadear a ação que você precisa, como um botão.

Na minha experiência, a primeira resposta, ou seja, simplesmente definindo delaysContentTouches para YES, não muda nada em relação ao problema. Os botões ainda não vai entregar resultados de rastreamento para a exibição de rolagem. A terceira resposta é simples e muito útil. Graças sieroaoj!

No entanto, para a terceira resposta ao trabalho que você set delaysContentTouches também precisa YES. Caso contrário, o touchesEnded método também será chamado para rastrear dentro da visão. Portanto, eu poderia resolver o problema:

  1. Substitua de botão por um simples costume UIView
  2. Coloque a bandeira "userInterationEnable = yes;" no método init
  3. Na vista substituir o método UIResponder "touchesEnded" aqui você pode acionar a ação que você

Em quarto lugar. conjunto delaysContentTouches para YES

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top