Verwenden von View.bounds, um Grenzen zu dienen
-
20-09-2019 - |
Frage
Ich arbeite an ein paar grundlegenden Apps/Dienstprogrammen/Spielen mit dem iPhone, um es besser zu machen.
Ich habe derzeit ein Setup, bei dem a CGRect
bewegt sich wo immer der Finger bewegt, aber ich will das nicht CGRect
außerhalb der bounds
des view
.
Originalmethode
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
startLocation = [touch locationInView:self];
if (startLocation.x < 33){
touchLocation.x = 33;
//NSLog(@"Touch At:%f, %f", touchLocation.x, touchLocation.y);
[self setNeedsDisplay];
}
if (startLocation.x > 288){
touchLocation.x = 288;
//NSLog(@"Touch At:%f, %f", touchLocation.x, touchLocation.y);
[self setNeedsDisplay];
}
if (startLocation.y < 84){
touchLocation.y = 84;
//NSLog(@"Touch At:%f, %f", touchLocation.x, touchLocation.y);
[self setNeedsDisplay];
}
if (startLocation.y > 460){
touchLocation.y = 460;
//NSLog(@"Touch At:%f, %f", touchLocation.x, touchLocation.y);
[self setNeedsDisplay];
}
else {
touchLocation = startLocation;
[self setNeedsDisplay];
}
}
Problem
Ich habe einige verschiedene Methoden davon ausprobiert, einschließlich der Verwendung &&
und es nur zu einer Aussage machen. Das boundaries
sind offensichtlich hart codiert, und ich bin mir nicht sicher, ob das manuell die manuell einstellen touchLocation
ist der beste Weg, um es zu behalten bounds
.
Das alles scheint mir albern, wenn ich leicht kann self.view.bounds
und die Begrenzung bekommen CGRect
. Wie benutze ich von bounds
um dies zu tun? Gibt es einen besseren Weg, um zu verhindern, dass es sich nicht einstellen, als einzustellen? touchLocation
manuell? Kann ich stattdessen irgendwie eine harte Begrenzung geben?
Was ist mit switch
Aussage? Würde das besser funktionieren als die versuchten?if
s?
Versuchen
Ich versuche jetzt, die unten veröffentlichte Methode von @Brad Goss zu verwenden, aber es funktioniert nicht?
Touch Started: (319.000000,350.000000)
Touch Result: (319.000000,350.000000)
Boundaries calculated: X:(0.000000,288.000000) Y(0.000000,328.000000)
Berührung begonnen ist der tatsächliche Startakt. Touch -Ergebnis sollte das geänderte Ergebnis sein.
Das obige Protokoll zeigt es außerhalb des definierten bounds
, auch bekannt als nicht arbeitet. Ich werde den Code, den er geschrieben hat, nicht neu veröffentlichen, weil er genau dasselbe ist.
Versuchsproblem
Ich habe das Problem entdeckt. Dies ist die gleiche Typsituation wie oben, jedoch mit der Anmeldung für die einzelnen Werte, die sie festgelegt sind.
Touch Started: (293.000000,341.000000)
min x:288.000000
max x:293.000000
min y:328.000000
max y:341.000000
Touch Result: (293.000000,341.000000)
Boundaries calculated: X:(0.000000,288.000000) Y(0.000000,328.000000)
Ich habe es nicht herausgefunden, ich habe es hier gepostet, sobald ich es entdeckt habe. Ansonsten würde ich vergessen, überhaupt zu aktualisieren, Heh hinzuzufügen.
Ich werde zurückgehen und genau sehen, was in jeder der möglichen Situationen vor sich geht.
Fehler
Fand ein anderes Problem, den Code, der das berechnet boundaries
subtracts
von dem maximums
, aber nicht add
zum minimums
. Dies ist wichtig, da dies das ist, was das ist boundary
ist für, um das zu stoppen rect
vom Bildschirm ausgehen.
maxX = b.origin.x + b.size.width/* - [box bounds].size.width */;
minX = b.origin.x/* + [box bounds].size.width */;
maxY = b.origin.y + b.size.height/* - [box bounds].size.height */;
minY = b.origin.y?/* + [box bounds].size.height */;
Mit diesem fest kann ich weiter an dem ursprünglichen Problem arbeiten.
Fehler 2
Okay, ich habe ein anderes Problem behoben. Ich fügte dem hinzu y
Wert, wenn es angezeigt wurde. Ich habe vergessen, es in diesen neuen Code hinzuzufügen/ihn zu erwähnen. Der Code sieht jetzt so aus:
maxX = b.origin.x + b.size.width/* - [box bounds].size.width */;
minX = b.origin.x/* + [box bounds].size.width */;
maxY = b.origin.y + b.size.height/* - [box bounds].size.height + 20*/;
minY = b.origin.y/* + [box bounds].size.height + 20*/;
Die Größe des angezeigten Kreises befindet sich innerhalb von a 64px CGRect
, Also 20px
war ausreichend, um den Kreis direkt über dem Daumen anzuzeigen. Obwohl dies festgelegt ist, hat es immer noch nicht geholfen, unser ursprüngliches Problem zu lösen.
Obere linke Ecke:
Touch Started: (14.000000,20.000000)
min x:14.000000
max x:32.000000
min y:20.000000
max y:84.000000
Touch Result: (32.000000,84.000000)
Boundaries calculated: X:(32.000000,288.000000) Y(84.000000,276.000000)
Es funktioniert so wie es sollte, aber ich bin verwirrt darüber, warum die richtigen Werte herauskommen MAX
Anstatt von MIN
. Hier ist etwas durcheinander.
Obere rechte Ecke:
Touch Started: (303.000000,21.000000)
min x:288.000000
max x:303.000000
min y:21.000000
max y:84.000000
Touch Result: (303.000000,84.000000)
Boundaries calculated: X:(32.000000,288.000000) Y(84.000000,276.000000)
Es hindert mich daran, wieder von der Spitze des Bildschirms zu gehen MAX
Anstatt von MIN
. Ich bin immer noch in der Lage, nach rechts abzufliegen, wie oben gezeigt.
Rechte untere Ecke:
Touch Started: (317.000000,358.000000)
min x:288.000000
max x:317.000000
min y:276.000000
max y:358.000000
Touch Result: (317.000000,358.000000)
Boundaries calculated: X:(32.000000,288.000000) Y(84.000000,276.000000)
Es scheitert in beiden Richtungen. Jetzt kommen die tatsächlichen Werte von MAX
, und die maximalen Werte kommen von MIN
. WTF?
Untere linke Ecke:
Touch Started: (8.000000,354.000000)
min x:8.000000
max x:32.000000
min y:276.000000
max y:354.000000
Touch Result: (32.000000,354.000000)
Boundaries calculated: X:(32.000000,288.000000) Y(84.000000,276.000000)
Vorhersehbar funktionierte es nur für den Mindestwert. Ich bin immer noch sehr verwirrt darüber, was diese Funktionen tun sollen. Einsicht wäre sehr geschätzt!
Gelöst!
Unsere lange Straße zieht zum Glück zu Ende. Also, weil ich keine Ahnung hatte, hier ist was MIN
und MAX
tun. Es war mir aufgrund der Verwirrung, die stattgefunden hatte, anfangs anfangs offensichtlich.
MAX(x,y) will output the larger of the two numbers
// MAX(13,37) = 37
MIN(x,y) will output the smallest of the two numbers
// MIN(13,37) = 13
Dies ist also, was Sie tun müssen, um diese Funktionen in dieser Situation korrekt zu nutzen:
1. Berechnen Sie die maximalen und minimalen Werte für x und y.
Der niedrigste Wert für jeden wird berechnet als
view.origin + keepOnScreenRect.width
Der höchste Wert von jedem wird berechnet als
view.origin + view.size.height/width - keepOnScreenRect.height/width
Vergessen Sie nicht den Offset für den Finger!
Wenn Sie das tun, was ich getan habe, und die KeeponScrect -Sichtweise etwas über dem Finger des Benutzers positionieren lassen, sollten Sie den zusätzlichen Offset nur zum Maximalwert von y hinzufügen, da der Mindestwert von y der untere Bildschirm/die untere Ansicht ist, welche Sie sind physisch nicht in der Lage, niedriger als 0 bei zu gehen.
Wenn Sie sich fragen, warum dies geschehen ist, liegt es daran, dass der Benutzer nicht durch seinen Finger sehen kann.
2. Holen Sie sich den Standort der Berührung an touchesBegan:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
startTouchLocation = [touch locationInView:self];
NSLog(@"Touch Started: (%f,%f)", startTouchLocation.x, startTouchLocation.y);
3. Wenden Sie die mathematischen Einschränkungen an:
Erstens bekommen wir das MAX
, oder höchstem Wert, sowohl vom niedrigstmöglichen Wert gemäß unseren Grenzen, minX
, und startTouchLocation
, zum X
. Dies berechnet die Grenze für die linke Seite des Bildschirms. Das Ergebnis davon ist auf currentTouchLocation
.
currentTouchLocation.x = MAX(minX, startTouchLocation.x);
Zweitens bekommen wir das MIN
, oder niedrigster Wert, sowohl vom höchstmöglichen Wert gemäß unseren Grenzen, maxX
, und currentTouchLocation
, zum X
. Beachten Sie, dass wir den Ort der ursprünglichen Berührung nicht verwenden, sondern den daraus resultierenden Ort der MAX
Funktion, die wir gerade verwendet haben. Dieser Wert wurde bereits auf die linke Seite des Bildschirms überprüft, sodass wir die rechte überprüfen.
currentTouchLocation.x = MIN(maxX, currentTouchLocation.x);
Das gibt uns eine X
Ort, der garantiert in unseren Grenzen liegt. Wir führen dann das gleiche auf Y
.
currentTouchLocation.y = MAX(minY, startTouchLocation.y);
currentTouchLocation.y = MIN(maxY, currentTouchLocation.y);
Mit all dem beendet können wir jetzt die Aussicht erkennen, sich neu zu zeichnen und keine Angst mehr zu haben, unser hübsches kleines Rechteck in irgendeiner Weise abzuschneiden.
[self setNeedsDisplay];
Fertiges Produkt
/* Generates the limits based on the view's size, taking into account
the width/height of the rect being displayed in it. This should only
be run once, unless the size of the view changes, in which case limits
would have to be recalculated. The same goes for if you were to change
the size of the displaying rect after calculation */
- (void)boundsCalculation {
CGRect viewBounds = [self bounds];
// calculate constraints
maxX = viewBounds.origin.x + viewBounds.size.width - 32;
minX = viewBounds.origin.x + 32;
maxY = viewBounds.origin.y + viewBounds.size.height - 32;
minY = viewBounds.origin.y + 84;
NSLog(@"Boundaries calculated: X:(%f,%f) Y(%f,%f)", minX, maxX, minY, maxY);
}
/* Magic goodness that happens when the user touches the screen.
Note that we don't calculate the bounds every time the user touches
the screen, that would be silly. */
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
startTouchLocation = [touch locationInView:self];
NSLog(@"Touch Started: (%f,%f)", startTouchLocation.x, startTouchLocation.y);
// apply constraints
// highest x value between the lowest allotted x value and touch
currentTouchLocation.x = MAX(minX, startTouchLocation.x);
// lowest x value between the highest allotted x value and touch
currentTouchLocation.x = MIN(maxX, currentTouchLocation.x);
// highest y value between the lowest allotted y value and touch
currentTouchLocation.y = MAX(minY, startTouchLocation.y);
// lowest y value between the highest allotted y value and touch
currentTouchLocation.y = MIN(maxY, currentTouchLocation.y);
// NSLog(@"Touch Result: (%f,%f)", currentTouchLocation.x, currentTouchLocation.y);
// If you don't do this you won't see anything
[self setNeedsDisplay];
}
Heute war ein guter Tag zum Lernen.
Lösung
Sie möchten auf jeden Fall die Grenzen der Übersicht verwenden, um seine Bewegung einzuschränken.
Rufen Sie SetNeedsDisplay nicht so oft an. Nennen Sie es am Ende der Methode einmal. Sie zeichnen möglicherweise unnötig neu.
Ich würde so etwas wie das Folgende verwenden, um dies zu erreichen.
// define these variables where ever you'd like
static float maxX = 0.;
static float maxY = 0.;
static float minX = 0.;
static float minY = 0.;
- (void)setupView {
CGRect b = [self bounds];
// calculate constraints
maxX = b.origin.x + b.size.width/* - [box bounds].size.width */;
minX = b.origin.x;
maxY = b.origin.y + b.size.height/* - [box bounds].size.height */;
minY = b.origin.y;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
startLocation = [touch locationInView:self];
// apply constraints
touchLocation.x = MIN(maxX, startLocation.x);
touchLocation.x = MAX(minX, startLocation.x);
touchLocation.y = MIN(maxY, startLocation.y);
touchLocation.y = MAX(minY, startLocation.y);
[self setNeedsDisplay];
}