Teste de acertos em camada Somente a camada de retorno quando a metade inferior da camada é tocada

StackOverflow https://stackoverflow.com/questions/401040

Pergunta

Eu tenho uma subcamada em uma visão apoiada por camada. O conteúdo do subclayer é definido como uma reflex de imagem e é um retul 25x25.
Eu realizo um teste de sucesso na super camada quando os métodos TouchesBegan e Touchesmoved são invocados. De fato, o método de teste de acerto retorna a subcamada se for tocada, mas apenas se a metade inferior da imagem for tocada. Se a metade superior da imagem for tocada, ela retornará o super -campeão.

Sei que o sistema operacional do iPhone compensa a tendência dos toques do usuário a serem mais baixos do que o pretendido. Mesmo se eu redimensionar a subcamada para um tamanho maior, 50x50, ele exibe o mesmo comportamento.

Alguma ideia?

Foi útil?

Solução 6

Obrigado Kevin ...

Acabei apenas refazendo meu código com o UIViews. Era muito problema apenas tentar descobrir por que o UIView não sabia que camada estava sendo tocada. Todo o meu raciocínio por trás da idéia era ter mais de 100 itens na tela ao mesmo tempo, e as camadas de pensamento seriam mais fáceis para o processador do que o UIViews. Eu tenho o aplicativo em funcionamento agora e 100 visualizações não estão dando soluços.

Minha sugestão para os outros é apenas seguir os testes de sucesso, quando possível, torna o código muito mais simples

Outras dicas

A documentação para o Hittest diz:

/* Returns the farthest descendant of the layer containing point 'p'.
 * Siblings are searched in top-to-bottom order. 'p' is in the
 * coordinate system of the receiver's superlayer. */

Então você precisa fazer (algo assim):

CGPoint thePoint = [touch locationInView:self];
thePoint = [self.layer convertPoint:thePoint toLayer:self.layer.superlayer];
CALayer *theLayer = [self.layer hitTest:thePoint];

(Repetindo a resposta de outro post por completude)

Parece que a camada não está apenas recebendo toques nos pixels inferiores. Em vez disso, parece que a camada "real" na tela e o conteúdo da camada são definidos por diferentes CGrects. A imagem é exibida nos cordinatos esperados, enquanto a camada que responde aos toques está compensada abaixo da imagem. Por baixo, quero dizer que a origem da imagem está em (200, 200) e a origem da camada que responde aos toques está em (200, 220).

Abaixo, estou postando algum código de teste que usei para recriar o problema. Primeiro, minha subclasse de visualização e depois meu controlador de visualização. Qualquer raciocínio por trás desse problema é muito apreciado.

Minha subclasse de visão:

#import "myView.h"
#import <QuartzCore/QuartzCore.h>


@implementation myView


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    CGPoint currentLocation = [[touches anyObject] locationInView:self];

    CALayer *currentLayer = [self.layer hitTest:currentLocation];

    CGPoint center = [currentLayer position];

    NSLog([currentLayer valueForKey:@"isRootLayer"]);

    if(![currentLayer valueForKey:@"isRootLayer"]) {

        if (center.x != 200) {

            [currentLayer setPosition:CGPointMake(200.0f, 200.0f)];     

        } else {
            [currentLayer setPosition:CGPointMake(100.0f, 100.0f)];     

        }
    }
}


- (id)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        // Initialization code
    }
    return self;
}


- (void)drawRect:(CGRect)rect {
    // Drawing code
}


- (void)dealloc {
    [super dealloc];
}


@end

Meu controlador de vista:

#import "layerTestViewController.h"
#import <QuartzCore/QuartzCore.h>


#define ELEMENT_PERIOD_SIZE 50
#define ELEMENT_GROUP_SIZE 50

@implementation layerTestViewController





// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];

    CALayer  *myLayer = [CALayer layer];
    CGRect layerFrame =CGRectMake(0.0f, 0.0f, ELEMENT_GROUP_SIZE, ELEMENT_PERIOD_SIZE);
    myLayer.frame = layerFrame; 

    [myLayer setName:[NSString stringWithString:@"test"]];
    [myLayer setValue:[NSString stringWithString:@"testkey"] forKey:@"key"];

    UIGraphicsBeginImageContext(layerFrame.size);
    [[UIColor blueColor] set];
    UIRectFill(layerFrame);
    UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    myLayer.contents = (id)[theImage CGImage];
    myLayer.position = CGPointMake(100.0f, 100.0f);

    [self.view.layer addSublayer:myLayer];   

    [self.view.layer setValue:[NSString stringWithString:@"YES"] forKey:@"isRootLayer"];
    NSLog([self.view.layer valueForKey:@"isRootLayer"]);

}




- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
}


- (void)dealloc {
    [super dealloc];
}

@end

A resposta aceita não resolve o problema, mas a resposta de Schwa faz.

Eu tenho uma janela, um controlador de exibição e visualização. A visualização recebe toques e chamadas hitTest: em sua camada. Eu tive o mesmo problema e descobri que o ponto da vista está correto, mas em hitTest: A coordenada Y do ponto é de 20px, que é a altura da barra de status.

Mapeando o ponto para o sistema de coordenadas da superlayer, conforme sugerido por Schwa, esse problema é corrigido. O Super -Jayer "Misterioso" é a camada raiz da supervisão. No meu caso, é a camada da janela (quadro (0, 0, 320, 480)).

Se os toques estiverem sendo reconhecidos apenas na parte inferior, uma possibilidade é que outra subview esteja cobrindo a metade superior desta subview. Você tem várias subvisões ou apenas uma imagem? Caso você tenha várias subviews e qualquer um deles tenha a cor do plano de fundo como ClearColor, tente dar uma cor sólida para o teste. As maneiras pelas quais você saberá se sua subview está sendo coberta por outra subview ou não.

Espero que ajude.

Simplifiquei meu código para encontrar o problema. Eu só tenho uma subcamada na tela e sem subviews. O código listado acima é o que estou executando no simulador. Como existem apenas 2 camadas na tela, a camada de apoio da exibição do host e da subcamada que eu adicionei, nada deve interferir no teste de acerto.

Caso não estivesse claro, quando a parte superior da subcamada é tocada, o teste de acerto retorna a camada de apoio. Além disso, se eu tocar a camada de apoio em um ponto logo abaixo da subcamada, a subcamada será devolvida pelo teste de acerto.

É difícil de explicar, mas se você executar o código, ficará claro.

Obrigado

Quando tento seu código, recebo comportamentos quase corretos, exceto que os toques geralmente não são reconhecidos na borda da subcamada. Estou um pouco confuso quanto ao que está acontecendo. Você pode tentar fazer algo como quando registrar um toque, jogue uma nova camada minúscula onde ocorreu o toque (como um quadrado de 5x5 de alguma cor) e remova -o novamente 3 segundos depois. Dessa forma, você pode rastrear onde a CA acha que o toque ocorreu versus onde seu cursor realmente está.

BTW, você não precisa criar um CGIMAGE para o seu conteúdo azul, você pode simplesmente definir a camada backgroundColor para [UIColor blueColor].CGColor.

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