Сохранить кадр UIView после UIGestures - PullRequest
1 голос
/ 18 октября 2010

Я работаю над приложением для iPad, которое будет использовать UIGestureRecognizer, чтобы позволить пользователю панорамировать, масштабировать и вращать объекты (подкласс UIView) на экране.

Я понимаю, что свойство [UIView frame]недопустимо после выполнения преобразования, поэтому я пытаюсь взять значения моих UIGestureRecognizer и сохранить «фрейм» сам.

Вот код, который я использую для попытки этого (вы можете распознатьмного кода из примера проекта Apple, SimpleGestureRecognizers):

// Shape.h (partial)
@interface Shape : UIView <UIGestureRecognizerDelegate> {

    CGFloat                  centerX;
    CGFloat                  centerY;
    CGFloat                  rotatation;
    CGFloat                  xScale;
    CGFloat                  yScale;

}

// Shape.m (partial)
- (void)panPiece:(UIPanGestureRecognizer *)gestureRecognizer
{
    UIView *piece = [gestureRecognizer view];

    [self adjustAnchorPointForGestureRecognizer:gestureRecognizer];

    if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) {
        CGPoint translation = [gestureRecognizer translationInView:[piece superview]];
        self.centerX += translation.x;
        self.centerY += translation.y;

        [piece setCenter:CGPointMake([piece center].x + translation.x, [piece center].y + translation.y)];
        for ( HandleView *h in [self handles] ) {
            [h setCenter:CGPointMake([h center].x + translation.x, [h center].y + translation.y)];
            [h setNeedsDisplay];
        }
    [gestureRecognizer setTranslation:CGPointZero inView:[piece superview]];
    NSLog(@"(%.0f, %.0f, %.0f, %.0f) %.2f˚, (%.2fx, %.2fx)", [self frame].origin.x, [self frame].origin.y, [self frame].size.width, [self frame].size.height, [self rotation], [self xScale], [self yScale]);
    }
}

// rotate the piece by the current rotation
// reset the gesture recognizer's rotation to 0 after applying so the next callback is a delta from the current rotation
- (void)rotatePiece:(UIRotationGestureRecognizer *)gestureRecognizer
{
    [self adjustAnchorPointForGestureRecognizer:gestureRecognizer];

    if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) {
        CGFloat rot = [self normalizeRotation:[gestureRecognizer rotation]];
        self.rotation += rot * 180.0 / M_PI;
        NSLog(@"Rotation: %.12f", [gestureRecognizer rotation]);
        [gestureRecognizer view].transform = CGAffineTransformRotate([[gestureRecognizer view] transform], [gestureRecognizer rotation]);
        [gestureRecognizer setRotation:0];
        NSLog(@"(%.0f, %.0f, %.0f, %.0f) %.2f˚, (%.2fx, %.2fx)", [self frame].origin.x, [self frame].origin.y, [self frame].size.width, [self frame].size.height, [self rotation], [self xScale], [self yScale]);
    }
}

// scale the piece by the current scale
// reset the gesture recognizer's rotation to 0 after applying so the next callback is a delta from the current scale
- (void)scalePiece:(UIPinchGestureRecognizer *)gestureRecognizer
{
    [self adjustAnchorPointForGestureRecognizer:gestureRecognizer];

    if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) {
        self.xScale *= [gestureRecognizer scale];
        self.yScale *= [gestureRecognizer scale];
        [gestureRecognizer view].transform = CGAffineTransformScale([[gestureRecognizer view] transform], [gestureRecognizer scale], [gestureRecognizer scale]);
    [gestureRecognizer setScale:1];
        NSLog(@"(%.0f, %.0f, %.0f, %.0f) %.2f˚, (%.2fx, %.2fx)", [self frame].origin.x, [self frame].origin.y, [self frame].size.width, [self frame].size.height, [self rotation], [self xScale], [self yScale]);
    }
}

Из-за некоторых странностей, которые я заметил при поворотах, я реализовал следующий метод, чтобы помочь сохранить точное значение вращения:

- (CGFloat) normalizeRotation:(CGFloat)rot
{
    if (abs(rot) > 0.05) {
        if (rot > 0) {
            rot -= M_PI;
        } else {
            rot += M_PI;
        }
        return [self normalizeRotation:rot];
    } else {
        return rot;
    }
}

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

Проблема в том, что после того, как пользователь перемещает, изменяет размеры и поворачивает UIView, я хочу позволить ему коснуться его и дать ему «ручки», которые позволяютизменение размера, отличное от «квадратного» изменения, которое дает сжатие (т. е. когда вы используете жест сжатия, вы увеличиваете или уменьшаете размер в одинаковом соотношении для x и y).Теперь, даже с кодом выше, сохраненные значения не всегда точны.

«Ручки», которые я использую, представляют собой просто 10x10 точек, которые должны идти в каждом углу и на полпути вниз по каждой «стороне» рамки / прямоугольника UIView.Когда я впервые ставлю квадрат и нажимаю на него, чтобы получить ручки, прежде чем делать что-либо еще, маркеры появляются в соответствующем месте.Когда я перемещаю, изменяю размеры и поворачиваю объект, затем нажимаю на него, все ручки смещаются от формы на некоторое количество.Обычно он составляет около 20 пикселей.

Являются ли значения в объектах UIGestureRecognizer просто недостаточно точными?Похоже, что это не так, потому что эти значения используются для изменения объекта на экране, и это точно.

Я почти уверен, что у меня нет возможности получить реальное представление офрейм UIView после того, как он так много возился, но где же недостаток в моем пользовательском коде, который дает мне плохие значения?Я теряю точность при преобразовании между градусами и радианами?

На заметке, связанной с этим: у Apple, очевидно, есть внутренний код, который отслеживает, как нарисовать представление, которое было переведено / преобразовано.Рамка сплошного цвета, которую я сейчас использую, перемещается, масштабируется и поворачивается правильно.Итак, есть ли способ получить доступ к значениям, которые они используют для отображения переведенного / преобразованного UIView?

Спасибо!

...