Question

Je travaille sur quelques applications de base / Utilitaires / jeux avec l'iPhone pour obtenir une meilleure prise sur elle.

J'ai actuellement une configuration où un CGRect se déplace là où le doigt se déplace, mais je ne veux pas le CGRect d'aller en dehors de la bounds du view.

Méthode originale

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

Problème

J'ai essayé quelques méthodes différentes de celui-ci, y compris l'utilisation && et d'en faire une seule déclaration. Les boundaries sont évidemment codé en dur, et je ne suis pas sûr que le réglage manuel du touchLocation est la meilleure façon de le maintenir en bounds.

Tout cela me semble stupide quand je peux facilement self.view.bounds et obtenir le CGRect englobante. Comment puis-je faire usage de bounds pour le faire? Y at-il une meilleure façon de l'empêcher de se produire autre que la mise en touchLocation manuellement? Puis-je placer en quelque sorte une limite stricte à ce sujet à la place?

Qu'en est-il une déclaration de switch? Est-ce que travailler mieux que les tentatives de-ifs?


Tentative

Je tente maintenant d'utiliser la méthode de @Brad Goss affiché ci-dessous, mais il ne fonctionne pas?

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

tactile est en route la touche de départ réelle. Résultat contact doit être le résultat modifié.

Le journal ci-dessus montre à l'extérieur de la bounds définie, alias ne fonctionne pas. Je ne vais pas reposter le code qu'il a écrit parce qu'il est exactement le même.


Tentative problème

Je l'ai découvert le problème. Ceci est la même situation de type comme ci-dessus, mais avec la journalisation pour les valeurs individuelles telles qu'elles sont définies.

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)

Je n'ai pas pensé à elle, je l'ai posté ici dès que je l'ai découvert. Sinon j'oublier de mettre à jour à tous, ADD heh.

Je vais revenir en arrière et voir exactement ce qui se passe dans chacune des situations possibles.


Erreur

trouvé un autre problème, le code qui calcule la boundaries de subtracts du maximums, mais ne add pas au minimums. Ceci est important car c'est ce que le boundary est pour, d'arrêter le rect d'aller hors de l'écran.

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

Avec ce fixe, je peux continuer à travailler sur le problème d'origine.


Erreur 2

D'accord, je l'ai résolu un autre problème. J'ajoutais à la valeur y quand il est affiché. J'ai oublié de l'ajouter dans ce nouveau code / mentionner. Le code ressemble maintenant à ceci:

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

La taille du cercle affiché est à l'intérieur d'un 64px CGRect, donc 20px était suffisante pour afficher le cercle juste au-dessus du pouce. Bien que ce soit fixé, il n'a toujours pas aidé à résoudre notre problème d'origine.

Coin supérieur gauche:

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)

Il fonctionne comme il se doit, mais je suis confus quant à la raison pour laquelle les valeurs correctes sortent de MAX au lieu de MIN. Quelque chose est mélangé ici.

coin supérieur droit:

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)

Il me empêche d'aller du haut de l'écran, encore une fois de MAX au lieu de MIN. Je suis encore capable de voler au large de la droite, comme indiqué ci-dessus.

coin en bas à droite:

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)

Il est à défaut dans les deux directions. Maintenant, les valeurs réelles proviennent de MAX, et les valeurs maximales viennent MIN. WTF?

coin en bas à gauche:

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)

On pouvait s'y attendre, il ne fonctionnait pour la valeur minimale. Je suis encore très confus quant à ce que ces fonctions sont censés faire. Aperçu serait très apprécié!


SOLVED!

Notre longue route tire à sa fin, heureusement. Donc, parce que je n'avais aucune idée, voici ce que font MIN et MAX. Il n'a pas été initially évident pour moi en raison de la confusion qui avait eu lieu.

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

Voilà donc ce que vous devez faire pour utiliser correctement ces fonctions dans cette situation:

1. Calculer le maximum et les valeurs minimales pour X et Y.

La valeur la plus basse pour chaque est calculée comme

view.origin + keepOnScreenRect.width  

La valeur la plus élevée est chaque calculée comme étant de

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

Ne pas oublier le décalage pour le doigt! Si vous faites ce que je faisais, et avez le keepOnScreenRect positionné légèrement au-dessus du doigt de l'utilisateur, vous ne devriez ajouterez le supplément offset à la valeur maximale de Y, comme la valeur minimale de Y est le bas de l'écran / vue, qui vous êtes physiquement incapable d'aller plus bas que 0 à.

Si vous vous demandez pourquoi cela est fait, il est parce que l'utilisateur ne peut pas voir à travers son / son doigt.

2. Obtenez l'emplacement du contact sur 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. Appliquer les contraintes mathématiques:

Tout d'abord, nous obtenons la MAX, ou valeur la plus élevée, à la fois la plus petite valeur possible en fonction de nos limites, minX et startTouchLocation, pour X. Cela calcule la limite pour le côté gauche de l'écran. Le résultat de ce paramètre est réglé currentTouchLocation.

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

En second lieu, nous obtenons la MIN ou la valeur la plus faible, à la fois la valeur la plus élevée possible en fonction de nos limites, maxX et currentTouchLocation, pour X. Notez que nous n'utilisons pas l'emplacement du contact d'origine, mais l'emplacement résultant de la fonction MAX que nous venons d'utiliser. Cette valeur a déjà été vérifiée pour le côté gauche de l'écran, donc nous vérifier le droit.

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

Cela nous donne un emplacement X qui est garanti dans nos limites. Nous effectuons ensuite la même chose sur Y.

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

Avec tout cela terminé, nous pouvons maintenant dire en vue de se redessiner et ne craignent plus avoir coupé notre joli petit rectangle de quelque façon.

[self setNeedsDisplay];

Produit fini

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

Aujourd'hui était une bonne journée pour l'apprentissage.

Était-ce utile?

La solution

Vous voulez certainement utiliser les limites de celui-ci est superview de limiter son mouvement.

Ne pas appeler setNeedsDisplay souvent. Appelez une fois à la fin de la méthode. Vous redessinez potentiellement inutilement.

J'utiliser quelque chose comme ce qui suit pour y parvenir.

// 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];
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top