Вопрос

Я работаю над несколькими основными приложениями/утилитами/играми с iPhone, чтобы лучше понять это.

В настоящее время у меня есть установка, где CGRect Двигается, куда бы движется палец, однако я не хочу CGRect Выйти за пределы bounds принадлежащий view.

Оригинальный метод

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

Проблема

Я попробовал несколько разных методов этого, включая использование && и сделать это только одно заявление. А boundaries явно жестко закодированы, и я не уверен, что вручную настраивать touchLocation лучший способ сохранить его в bounds.

Все это кажется мне глупо, когда я легко могу self.view.bounds и получить ограничивающий CGRect. Анкет Как использовать bounds сделать это? Есть ли лучший способ предотвратить это, кроме настройки touchLocation вручную? Могу ли я как -то поставить на него жесткий предел?

А как насчет switch утверждение? Будет ли это работать лучше, чем попытка-ifs?


Пытаться

Теперь я пытаюсь использовать метод @brad Goss, размещенный ниже, однако он не работает?

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

Прикосновение запускается фактическим начальным прикосновением. Прикосновение Результат должен быть измененным результатом.

Приведенный выше журнал показывает его вне определенного bounds, он же не работает. Я не собираюсь репортировать код, который он написал, потому что он точно такой же.


Проблема попытки

Я обнаружил проблему. Это та же самая ситуация, что и выше, но с регистрацией для отдельных значений, как они установлены.

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)

Я не понял это, я опубликовал это здесь, как только обнаружил. В противном случае я бы вообще забыл обновить, добавить хех.

Я собираюсь вернуться и посмотреть, что именно происходит в каждой из возможных ситуаций.


Ошибка

Нашел другую проблему, код, который вычисляет boundaries subtracts от maximums, но нет add в minimums. Анкет Это важно, так как это то, что boundary для остановки rect от выхода с экрана.

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

С помощью этого я могу продолжать работать над исходной проблемой.


Ошибка 2

Хорошо, я исправил еще одну проблему. Я добавил в y значение, когда это отображалось. Я забыл добавить его в этот новый код/упомянуть его. Код теперь выглядит так:

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

Размер отображаемого круга находится внутри 64px CGRect, так 20px было достаточно, чтобы показать круг чуть выше большого пальца. Хотя это исправлено, это все еще не помогло решить нашу первоначальную проблему.

Левый верхний угол:

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)

Это работает так, как должно, но я не понимаю, почему правильные значения выходят из MAX вместо MIN. Анкет Что -то здесь смешано.

Верхний правый угол:

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)

Это мешает мне уйти с верхней части экрана, опять же от MAX вместо MIN. Анкет Я все еще могу вылететь с правого, как показано выше.

Правый нижний угол:

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)

Это терпит неудачу в обоих направлениях. Теперь фактические значения поступают из MAX, и максимальные значения исходят от MIN. Анкет Wtf?

Нижний левый угол:

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)

Как и ожидалось, это работало только на минимальное значение. Я все еще очень смущен тем, что должны делать эти функции. Понимание будет очень оценено!


Решен!

К счастью, наша длинная дорога подходит к концу. Итак, потому что я понятия не имел, вот что есть MIN а также MAX делать. Первоначально это было не очевидно из -за путаницы, которая произошла.

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

Так что это то, что вы должны сделать, чтобы правильно использовать эти функции в этой ситуации:

1. Рассчитайте максимальные и минимальные значения для x и y.

Самое низкое значение для каждого рассчитывается как

view.origin + keepOnScreenRect.width  

Высшее значение каждого рассчитывается как

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

Не забудьте о смещении для пальца!
Если вы делаете то, что я делал, и имеете место, расположенное немного выше пальца пользователя, вы должны добавить только дополнительное смещение к максимальному значению y, так как минимальное значение y - нижняя часть экрана/вид, который, который Вы физически не можете идти ниже 0 в.

Если вам интересно, почему это сделано, это потому, что пользователь не может видеть сквозь свой палец.

2. Получите расположение ощущения 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. Примените математические ограничения:

Во -первых, мы получаем MAX, или самое высокое значение, обоих самых низких значений в соответствии с нашими пределами, minX, а также startTouchLocation, за X. Анкет Это рассчитывает предел для левой стороны экрана. Результат этого установлен на currentTouchLocation.

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

Во -вторых, мы получаем MIN, или самое низкое значение, обоих максимально возможных значений в соответствии с нашими пределами, maxX, а также currentTouchLocation, за X. Анкет Обратите внимание, что мы не используем местоположение исходного прикосновения, а в результате места MAX Функция мы только что использовали. Это значение уже было проверено на левую сторону экрана, поэтому мы проверяем правое.

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

Это дает нам X Место, которое гарантированно будет в наших пределах. Затем мы выполняем то же самое на Y.

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

С учетом всего этого мы можем теперь сказать вид, чтобы перерисовать себя и больше не бояться, что наш прекрасный маленький прямоугольник отрезал каким -либо образом.

[self setNeedsDisplay];

Готовый продукт

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

Сегодня был хороший день для обучения.

Это было полезно?

Решение

Вы определенно хотите использовать границы его надзора, чтобы ограничить его движение.

Не звоните SetNeedSdisplay, это часто. Назовите это один раз в конце метода. Вы потенциально перерисовываете ненужные.

Я бы использовал что -то вроде следующего, чтобы сделать это.

// 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];
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top