UIPinchGestureRecognizer размещает сжатый вид между двумя пальцами

Я успешно реализовал щепотку масштабирования представления. Тем не менее, вид не позиционирует себя там, где я хотел бы его видеть. Для stackoverflowers с iPad я хотел бы, чтобы мое представление было центрировано, как в iPad Photos.app: когда вы сжимаете и масштабируете альбом, фотографии представляются в расширяющемся представлении. Этот вид расположен приблизительно по центру с верхним правым углом на первом пальце и нижним левым пальцем на другом пальце. Я смешал это с распознавателем панорамирования, но таким образом пользователю всегда приходится сжимать, а затем панорамировать, чтобы настроить.

Вот такое графическое объяснение, я мог бы опубликовать видео моего приложения, если это неясно (не секрет, я пытаюсь воспроизвести Photos.app для iPad...)

Итак, для начального положения пальцев, начиная масштабирование:

введите здесь описание изображения

Это настоящий «увеличенный» кадр на данный момент. Квадрат больше, но положение ниже пальцев

с учетом начальной позиции

Вот что я хотел бы иметь: тот же размер, но разные origin.x и y :

введите здесь описание изображения

(извините за мои плохие навыки фотошопа ^^)


person Thomas Joulin    schedule 09.02.2011    source источник
comment
Привет, Томас, меня это тоже очень интересует. Вы нашли какие-либо решения по этому поводу? У вас есть примеры кодов? спасибо~   -  person ludo    schedule 11.10.2011
comment
У меня не было времени вернуться к этой проблеме, но ответ @md_develop выглядит великолепно. Я постараюсь найти время, чтобы обновить свой код и принять ответ, если это сработает.   -  person Thomas Joulin    schedule 11.10.2011


Ответы (2)


Вы можете получить CGPoint средней точки между двумя пальцами с помощью следующего кода в методе handlingPinchGesture.

CGPoint point = [sender locationInView:self];

Весь мой метод handlePinchGesture приведен ниже.

/*
instance variables

CGFloat lastScale;
CGPoint lastPoint;
*/

- (void)handlePinchGesture:(UIPinchGestureRecognizer *)sender {
    if ([sender numberOfTouches] < 2)
        return;

    if (sender.state == UIGestureRecognizerStateBegan) {
        lastScale = 1.0;
        lastPoint = [sender locationInView:self];
    }

    // Scale
    CGFloat scale = 1.0 - (lastScale - sender.scale);
    [self.layer setAffineTransform:
        CGAffineTransformScale([self.layer affineTransform], 
                               scale, 
                               scale)];
    lastScale = sender.scale;

    // Translate
    CGPoint point = [sender locationInView:self];
    [self.layer setAffineTransform:
        CGAffineTransformTranslate([self.layer affineTransform], 
                                   point.x - lastPoint.x, 
                                   point.y - lastPoint.y)];
    lastPoint = [sender locationInView:self];
}
person mishimay    schedule 08.03.2011
comment
как это может работать, если [sender locationInView:self] всегда возвращает одну и ту же точку, среднюю точку между двумя сжимающими пальцами? - person Guy; 25.03.2012
comment
Средняя точка @Guy меняется после UIGestureRecognizerStateBegan, потому что вы отодвигаете или приближаете пальцы. locationInView:self возвращает центроид между двумя пальцами. Эта часть работает. Хотя через 1 час я все еще не могу заставить это работать в своем приложении, где у меня есть куча слоев, которые мне нужно переместить. - person Martin Berger; 10.12.2012
comment
Я использовал этот метод, и представление переведено правильно. Однако способ перевода не такой гладкий, как приложение Photo. - person Tien Nguyen; 12.08.2013
comment
@mishimay, если я добавлю подслой с именем _myLayer и заменю self.layer в вашем коде на _myLayer, ваш код не будет работать правильно. почему и как исправить? заранее спасибо. - person Gaojin Hsu; 03.08.2017

Взгляните на пример проекта Touches. В частности, эти методы могут помочь вам:

// scale and rotation transforms are applied relative to the layer's anchor point
// this method moves a gesture recognizer's view's anchor point between the user's fingers
- (void)adjustAnchorPointForGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
    if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
        UIView *piece = gestureRecognizer.view;
        CGPoint locationInView = [gestureRecognizer locationInView:piece];
        CGPoint locationInSuperview = [gestureRecognizer locationInView:piece.superview];

        piece.layer.anchorPoint = CGPointMake(locationInView.x / piece.bounds.size.width, locationInView.y / piece.bounds.size.height);
        piece.center = locationInSuperview;
    }
}

// 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) {
        [gestureRecognizer view].transform = CGAffineTransformScale([[gestureRecognizer view] transform], [gestureRecognizer scale], [gestureRecognizer scale]);
        [gestureRecognizer setScale:1];
    }
}
person Felix    schedule 10.02.2011
comment
спасибо, но использование view.transform также изменяет размеры моих подзаголовков... Есть ли способ предотвратить это? - person Thomas Joulin; 10.02.2011
comment
#import ‹QuartzCore/QuartzCore.h› — это нужно для anchorPoint - person Jake Graham Arnold; 11.07.2013