Layer Hit -Test nur zurückkehrende Schicht, wenn die untere Hälfte der Schicht berührt wird

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

Frage

Ich habe einen Unterschicht auf einer schichtrückversteigten Ansicht. Der Inhalt des Sublayer ist auf einen Bildrefium eingestellt und ist ein 25x25 -Rechtek.
Ich führe einen Hit -Test auf der Superschicht durch, wenn der TouchesBegan und die berührungsmischen Methoden aufgerufen werden. Die Hit -Testmethode gibt den Unterschicht tatsächlich zurück, wenn er berührt wird, jedoch nur, wenn die untere Hälfte des Bildes berührt wird. Wenn die obere Hälfte des Bildes berührt wird, gibt es stattdessen die Superlayer zurück.

Ich weiß, das iPhone -Betriebssystem kompensiert die Tendenz, dass Benutzerberührungen niedriger sind als beabsichtigt. Auch wenn ich die Größe des Unterschichts auf eine größere Größe 50x50 ändern kann, weist er das gleiche Verhalten auf.

Irgendwelche Gedanken?

War es hilfreich?

Lösung 6

Danke Kevin ...

Am Ende habe ich nur meinen Code mit UIViews wiederholt. Es war zu viel Mühe, nur herauszufinden, warum die Uiview nicht wusste, welche Ebene berührt wurde. Meine ganze Argumentation hinter der Idee war, dass ich gleichzeitig mehr als 100 Elemente auf dem Bildschirm haben werde und dass die Schichten für den Prozessor einfacher wären als UIViews. Ich habe die App jetzt in Betrieb und 100 Aufrufe geben ihr keine Schluckauf.

Mein Vorschlag zu anderen ist, wenn möglich bei Treffer -Testen zu bleiben. Er macht den Code viel einfacher

Andere Tipps

In der Dokumentation für Hittest heißt es:

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

Sie müssen also (so etwas so):

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

(Wiederholung der Antwort aus einem anderen Beitrag zur Vollständigkeitswillen)

Es scheint, dass die Ebene nicht nur Berührungen auf den unteren Pixeln erhält. Stattdessen scheint es, dass die "tatsächliche" auf der Bildschirmschicht und der Inhalt der Ebene durch verschiedene CGrects definiert werden. Das Bild wird an den erwarteten Cordinaten angezeigt, während die Ebene, die auf Berührungen reagiert, unter dem Bild ausgefallen ist. Im Folgenden meine ich, dass der Ursprung des Bildes bei (200, 200) und der Ursprung der Schicht, die auf Berührungen reagiert, bei (200, 220) ist.

Im Folgenden poste ich einen Testcode, den ich verwendet habe, um das Problem neu zu erstellen. Zuerst meine Ansichtsunterklasse und dann mein Ansichtscontroller. Jegliche Begründung für dieses Problem wird sehr geschätzt.

Meine Ansichtsunterklasse:

#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

Mein Ansichtscontroller:

#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

Die akzeptierte Antwort löst das Problem nicht, aber die Antwort von Schwa.

Ich habe ein Fenster, einen Ansichtsregler und eine Ansicht. Die Ansicht erhält Berührungen und Anrufe hitTest: auf seiner Schicht. Ich hatte das gleiche Problem und fand heraus, dass der Punkt in der Ansicht korrekt ist, aber in hitTest: Die Y -Koordinate des Punktes ist 20px aus, was zufällig die Höhe der Statusleiste ist.

Durch die Zuordnung des Punktes auf das Koordinatensystem des Superlayers, wie von Schwa vorgeschlagen, ist dieses Problem behoben. Der "mysteriöse" Superlayer ist die Wurzelschicht der Übersicht. In meinem Fall handelt es sich um die Fensterebene (Rahmen (0, 0, 320, 480)).

Wenn nur im unteren Teil Berührungen erkannt werden, besteht eine Möglichkeit darin, dass eine andere Subview die obere Hälfte dieser Unteransicht abdeckt. Haben Sie mehrere Subviews oder nur ein Bild? Wenn Sie mehrere Unteransicht haben und eine von ihnen die Hintergrundfarbe als ClearColor hat, geben Sie ihnen eine solide Hintergrundfarbe zum Testen an. Auf diese Weise werden Sie wissen, ob Ihr Unteransicht von einer anderen Unteransicht abgedeckt wird oder nicht.

Ich hoffe, das hilft.

Ich habe meinen Code vereinfacht, um das Problem zu finden. Ich habe nur einen Unterschicht auf dem Bildschirm und keine Unteransicht. Der oben aufgeführte Code ist das, was ich im Simulator ausführe. Da es nur 2 Ebenen auf dem Bildschirm, die Backing -Ebene der Hostansicht und den Untermesser, den ich hinzugefügt habe, befinden, sollte nichts den Hit -Test beeinträchtigen.

Wenn es nicht klar war, dass der obere Teil des Unterschichts nicht klar ist, gibt der Treffer -Test stattdessen die Backing -Schicht zurück. Auch wenn ich die Hintergrundschicht an einem Punkt direkt unterhalb der Unterschicht berühre, wird der Unterschicht durch den Treffertest zurückgegeben.

Es ist schwer zu erklären, aber wenn Sie den Code ausführen, wird es klar.

Vielen Dank

Wenn ich Ihren Code versuche, bekomme ich fast korrektes Verhalten, außer dass Berührungen oft nicht am Rande des Unterschichts erkannt werden. Ich bin ein bisschen verwirrt darüber, was los ist. Vielleicht möchten Sie versuchen, so etwas wie beim Registrieren einer Berührung zu tun, eine neue winzige Ebene nach oben zu werfen, wo die Berührung aufgetreten ist (wie ein 5x5 -Quadrat mit etwas Farbe) und dann 3 Sekunden später erneut entfernen. Auf diese Weise können Sie nachverfolgen, wo CA der Meinung ist, dass die Berührung aufgetreten ist und wo Ihr Cursor tatsächlich ist.

Übrigens müssen Sie keine CGImage für Ihren blauen Inhalt erstellen. Sie können einfach die Ebene der Ebene festlegen backgroundColor zu [UIColor blueColor].CGColor.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top