Domanda

Ho un sublayer in una vista supportata da livelli. Il contenuto del sublay è impostato su Rif. Immagine ed è un rettangolo 25x25.
Eseguo un hit test sul super layer quando vengono invocati i metodi touchesBegan e touchesMoved. Il metodo dell'hit test, infatti, restituisce il sublayer se viene toccato, MA solo se viene toccata la metà inferiore dell'immagine. Se viene toccata la metà superiore dell'immagine, restituisce invece il superlayer.

So che il sistema operativo iPhone compensa la tendenza dei tocchi dell'utente a essere inferiore al previsto. Anche se ridimensiono il sublayer a dimensioni maggiori, 50x50, mostra lo stesso comportamento.

Qualche pensiero?

È stato utile?

Soluzione 6

Grazie Kevin ...

Ho finito per rifare il mio codice con UIViews. Era troppo disturbo solo cercando di capire perché l'UIView non sapeva quale livello veniva toccato. Tutto il mio ragionamento alla base dell'idea era che avrò sullo schermo più di 100 elementi contemporaneamente, e ho pensato che i livelli sarebbero stati più facili sul processore rispetto a UIVview. Ora ho l'app installata e funzionante e 100 visualizzazioni non gli danno alcun singhiozzo.

Il mio suggerimento per gli altri è solo attenersi ai hit test UIVview quando possibile, rende il codice molto più semplice

Altri suggerimenti

La documentazione per hitTest dice:

/* 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. */

Quindi devi fare (qualcosa del genere):

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

(Ripetendo la risposta di altri post per completezza)

Sembra che il livello non stia solo ricevendo tocchi sui pixel inferiori. Invece sembra che il "reale" sul livello dello schermo e i contenuti del livello sono definiti da diversi CGRect. L'immagine viene visualizzata alle coordinate previste, mentre il livello che risponde ai tocchi è sfalsato sotto l'immagine. Per sotto, intendo che l'origine dell'immagine è a (200, 200) e l'origine del livello che risponde ai tocchi è a (200, 220).

Di seguito sto pubblicando un codice di test che ho usato per ricreare il problema. Prima la mia sottoclasse di visualizzazione e poi il mio controller di visualizzazione. Qualsiasi ragionamento alla base di questo problema è molto apprezzato.

Sottoclasse My View:

#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

My View Controller:

#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

La risposta accettata non risolve il problema, ma la risposta di schwa sì.

Ho una finestra, un controller di visualizzazione e una vista. La vista riceve tocchi e chiama hitTest: sul suo livello. Ho avuto lo stesso problema e ho scoperto che il punto nella vista è corretto, ma in hitTest: la coordinata y del punto è 20px off, che risulta essere l'altezza della barra di stato.

Mappando il punto sul sistema di coordinate del superlayer come suggerito da schwa questo problema è stato risolto. Il "misterioso" superlayer è il livello principale della superview. Nel mio caso, è il livello della finestra (frame (0, 0, 320, 480)).

Se i tocchi vengono riconosciuti solo nella parte inferiore, una possibilità è che un'altra sottoview copra la metà superiore di questa sottoview. Hai più visualizzazioni secondarie o una sola immagine? Nel caso in cui tu abbia più visualizzazioni secondarie e ognuna di esse abbia il colore di sfondo come clearColor, prova a dargli un colore di sfondo solido per il test. In questo modo saprai se la tua sottoview viene coperta o meno da un'altra subview.

Spero che sia d'aiuto.

Ho semplificato il mio codice per trovare il problema. Ho solo un sublayer sullo schermo e nessuna subview. Il codice sopra elencato è quello che sto eseguendo nel simulatore. Poiché sullo schermo sono presenti solo 2 livelli, il livello di supporto della vista host e il sublayer che ho aggiunto, nulla dovrebbe interferire con il hit test.

Nel caso in cui non fosse chiaro, quando viene toccata la parte superiore del sottostrato, il hit test restituisce invece il livello di supporto. Inoltre, se tocco il livello di supporto in un punto appena sotto il sublayer, il sublayer viene restituito dal hit test.

È difficile da spiegare, ma se si esegue il codice, diventa chiaro.

Grazie

Quando provo il tuo codice, ottengo un comportamento quasi corretto, tranne per il fatto che i tocchi spesso non vengono riconosciuti ai margini del sublayer. Sono un po 'confuso su ciò che sta succedendo. Potresti provare a fare qualcosa di simile quando registri un tocco, getti un nuovo minuscolo livello nel punto in cui si è verificato il tocco (come un quadrato 5x5 di qualche colore) e poi rimuovilo di nuovo 3 secondi dopo. In questo modo è possibile tenere traccia di dove CA ritiene che si sia verificato il tocco rispetto a dove si trova effettivamente il cursore.

A proposito, non è necessario creare un CGImage per il contenuto blu, puoi semplicemente impostare backgroundColor del livello su [UIColor blueColor] .CGColor .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top