Pregunta

Estoy trabajando en algunas aplicaciones/utilidades/juegos básicos con el iPhone para obtener un mejor agarre.

Actualmente tengo una configuración donde un CGRect se mueve donde sea que se mueva el dedo, sin embargo, no quiero el CGRect para salir del bounds del view.

Método original

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

Problema

He probado algunos métodos diferentes de esto, incluido el uso && y haciéndolo solo una declaración. los boundaries obviamente están codificados, y no estoy seguro de que establezca manualmente el touchLocation es la mejor manera de mantenerlo en bounds.

Todo esto me parece una tontería cuando puedo fácilmente self.view.bounds Y consigue la delantera CGRect. ¿Cómo hago uso de bounds ¿para hacer esto? ¿Hay una mejor manera de evitar que ocurra aparte de la configuración? touchLocation ¿a mano? ¿Puedo darle un límite difícil de alguna manera?

Que tal un switch ¿declaración? ¿Eso funcionaría mejor que el intento?if¿s?


Intentar

Ahora estoy intentando utilizar el método de @Brad Goss publicado a continuación, sin embargo, no funciona?

Touch Started: (319.000000,350.000000)
Touch Result: (319.000000,350.000000)
Boundaries calculated: X:(0.000000,288.000000) Y(0.000000,328.000000)

El tacto iniciado es el toque inicial real. El resultado táctil debe ser el resultado cambiado.

El registro anterior lo muestra fuera del definido bounds, también conocido como no funciona. No voy a volver a publicar el código que escribió porque es exactamente el mismo.


Problema de intento

He descubierto el problema. Esta es la misma situación de tipo que anteriormente, pero con el registro de los valores individuales tal como se establecen.

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)

No lo he descubierto, lo publiqué aquí tan pronto como lo descubrí. De lo contrario, olvidaría actualizar en absoluto, agregar heh.

Voy a regresar y ver exactamente lo que está sucediendo en cada una de las posibles situaciones.


Error

Encontró otro problema, el código que calcula el boundaries subtracts desde el maximums, pero no add hacia minimums. Esto es importante ya que esto es lo que el boundary es para, para detener el rect de salir de la pantalla.

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

Con esto solucionado, puedo continuar trabajando en el problema original.


Error 2

Muy bien, he solucionado otro problema. Estaba agregando al y valor cuando se mostraba. Olvidé agregarlo a este nuevo código/mencionarlo. El código ahora se ve así:

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

El tamaño del círculo que se muestra está dentro de un 64px CGRect, asi que 20px fue suficiente para mostrar el círculo justo por encima del pulgar. Aunque esto se soluciona, todavía no ha ayudado a resolver nuestro problema original.

Esquina superior izquierda:

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)

Funciona como debería, pero estoy confundido sobre por qué los valores correctos están saliendo de MAX en vez de MIN. Algo se mezcla aquí.

Esquina superior derecha:

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)

Me impide salir de la parte superior de la pantalla, nuevamente de MAX en vez de MIN. Todavía puedo volar de la derecha, como se muestra arriba.

Esquina inferior derecha:

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)

Está fallando en ambas direcciones. Ahora los valores reales provienen de MAX, y los valores máximos provienen de MIN. WTF?

Esquina izquierda inferior:

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)

Como era de esperar, solo funcionó para el valor mínimo. Todavía estoy muy confundido sobre lo que se supone que deben hacer estas funciones. ¡La información sería muy apreciada!


¡Resuelto!

Nuestro largo camino llega a su fin, afortunadamente. Entonces, porque no tenía idea, esto es lo que MIN y MAX hacer. Inicialmente no era obvio para mí debido a la confusión que había tenido lugar.

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

Entonces, esto es lo que tiene que hacer para utilizar estas funciones correctamente en esta situación:

1. Calcule los valores máximos y mínimos para X e Y.

El valor más bajo para cada uno se calcula como

view.origin + keepOnScreenRect.width  

El valor más alto de cada uno se calcula como

view.origin + view.size.height/width - keepOnScreenRect.height/width

¡No olvides el desplazamiento del dedo!
Si está haciendo lo que hice, y tenga la colocación de servicios de guardia ligeramente por encima del dedo del usuario, solo debe agregar el desplazamiento adicional al valor máximo de y, ya que el valor mínimo de y es la parte inferior de la pantalla/vista, que No puedes pasar físicamente más bajo que 0 AT.

Si se pregunta por qué se hace esto, es porque el usuario no puede ver a través de su dedo.

2. Obtenga la ubicación del toque 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. Aplicar las restricciones matemáticas:

Primero, obtenemos el MAX, o valor más alto, tanto del valor más bajo posible según nuestros límites, minX, y startTouchLocation, por X. Esto calcula el límite para el lado izquierdo de la pantalla. El resultado de esto se establece en currentTouchLocation.

currentTouchLocation.x = MAX(minX, startTouchLocation.x);

Segundo, obtenemos el MIN, o valor más bajo, tanto del valor más alto posible según nuestros límites, maxX, y currentTouchLocation, por X. Tenga en cuenta que no estamos utilizando la ubicación del toque original, sino la ubicación resultante del MAX función que acabamos de usar. Este valor ya se ha verificado para el lado izquierdo de la pantalla, por lo que verificamos la derecha.

currentTouchLocation.x = MIN(maxX, currentTouchLocation.x);

Que nos da un X Ubicación garantizada para estar dentro de nuestros límites. Luego realizamos lo mismo en Y.

currentTouchLocation.y = MAX(minY, startTouchLocation.y);
currentTouchLocation.y = MIN(maxY, currentTouchLocation.y);

Con todo esto terminado, ahora podemos decir la vista de volver a dibujar y ya no temer que nuestro pequeño rectángulo sea cortado de ninguna manera.

[self setNeedsDisplay];

Producto terminado

/* 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];
}

Hoy fue un buen día para aprender.

¿Fue útil?

Solución

Definitivamente desea usar los límites de su supervisión para restringir su movimiento.

No llame a SetNeedSdisplay con tanta frecuencia. Llámalo una vez al final del método. Potencialmente estás volviendo a dibujar innecesariamente.

Usaría algo como lo siguiente para lograr esto.

// 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];
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top