Как увеличить / уменьшить масштаб объекта UIImage, когда пользователь зажимает экран?

Я хотел бы увеличивать / уменьшать масштаб объекта UIImage, когда пользователь выполняет стандартное щипковое действие в моем приложении. В настоящее время я использую UIImageView для отображения моего изображения, если эта деталь хоть как-то помогает.

Пытаюсь понять, как это сделать, но пока безуспешно.

Какие-нибудь подсказки?


person jpm    schedule 01.02.2009    source источник


Ответы (9)


Еще один простой способ сделать это - поместить ваш UIImageView в UIScrollView. Как я описываю здесь, вы необходимо установить contentSize представления прокрутки таким же, как ваш UIImageView's размер. Установите экземпляр контроллера в качестве делегата представления прокрутки и реализуйте методы viewForZoomingInScrollView: и scrollViewDidEndZooming:withView:atScale:, чтобы разрешить масштабирование щипком и панорамирование изображения. Фактически это то, что делает решение Бена, только немного более легким способом, поскольку у вас нет накладных расходов, связанных с полным веб-представлением.

Одна из проблем, с которой вы можете столкнуться, заключается в том, что масштабирование в представлении прокрутки осуществляется в виде преобразований, применяемых к изображению. Это может привести к размытости при высоких коэффициентах увеличения. Для чего-то, что можно перерисовать, вы можете следовать моим предложениям здесь, чтобы обеспечить более четкое изображение после завершения жеста сжатия. На этом этапе можно использовать решение hniels для изменения масштаба изображения.

person Brad Larson    schedule 01.02.2009
comment
Убедитесь, что вы изменили maximumZoomScale и / или minimumZoomScale :). - person Chris Prince; 11.02.2014

Как описывали другие, самое простое решение - поместить ваш UIImageView в UIScrollView. Я сделал это в файле .xib Interface Builder.

В viewDidLoad установите следующие переменные. Установите в качестве контроллера UIScrollViewDelegate.

- (void)viewDidLoad {
    [super viewDidLoad];
    self.scrollView.minimumZoomScale = 0.5;
    self.scrollView.maximumZoomScale = 6.0;
    self.scrollView.contentSize = self.imageView.frame.size;
    self.scrollView.delegate = self;
}

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

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
    return self.imageView;
}

В версиях до iOS9 вам также может потребоваться добавить этот пустой метод делегата:

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale
{
}

Документация Apple хорошо описывает, как это сделать. это:

person rogue    schedule 23.08.2014
comment
Можно удалить scrollViewDidEndZooming: withView: теперь я тестировал с iOS9 Xcode7 - person ElonChan; 02.03.2016
comment
Меня устраивает! Без реализации метода scrollViewDidEndZooming :. - person Johnny; 04.05.2017

Решение Шефали для UIImageView отлично работает, но требует небольшой модификации:

- (void)pinch:(UIPinchGestureRecognizer *)gesture {
    if (gesture.state == UIGestureRecognizerStateEnded
        || gesture.state == UIGestureRecognizerStateChanged) {
        NSLog(@"gesture.scale = %f", gesture.scale);

        CGFloat currentScale = self.frame.size.width / self.bounds.size.width;
        CGFloat newScale = currentScale * gesture.scale;

        if (newScale < MINIMUM_SCALE) {
            newScale = MINIMUM_SCALE;
        }
        if (newScale > MAXIMUM_SCALE) {
            newScale = MAXIMUM_SCALE;
        }

        CGAffineTransform transform = CGAffineTransformMakeScale(newScale, newScale);
        self.transform = transform;
        gesture.scale = 1;
    }
}

(Обратной стороной решения Шефали было то, что оно не масштабировалось непрерывно во время сжатия. Кроме того, при запуске нового сжатия текущий масштаб изображения сбрасывался.)

person JRV    schedule 19.04.2012
comment
Я хочу, чтобы жест панорамирования был включен после запуска жеста сжатия. Как это сделать? - person Gajendra K Chauhan; 28.06.2012
comment
@Gajendra: В этом случае, я думаю, вам следует использовать встраивание компонентов в режим прокрутки, который поддерживает оба варианта из коробки. - person JRV; 28.06.2012
comment
Но мне нужна функциональность как для жеста касания, так и для жеста щипка. Я также использую сетку (слои) в Imageview. Могу ли я узнать, можно ли использовать жест сжатия и жест касания в режиме прокрутки? - person Gajendra K Chauhan; 29.06.2012
comment
@GajendraKChauhan: просмотр прокрутки поддерживает масштабирование и панорамирование из коробки - просто не забудьте установить минимальный / максимальный масштаб масштабирования, но посмотрите также на ответ Брэда Ларсона. А если вам нужен жест касания, вы можете добавить его в качестве жеста. - person JRV; 29.06.2012
comment
@JRV, какие делегаты мне нужно добавить, чтобы распознать self.frame.size.width? - person ; 26.07.2015

Приведенный ниже код помогает увеличить UIImageView без использования UIScrollView:

-(void)HandlePinch:(UIPinchGestureRecognizer*)recognizer{
    if ([recognizer state] == UIGestureRecognizerStateEnded) {
        NSLog(@"======== Scale Applied ===========");
        if ([recognizer scale]<1.0f) {
            [recognizer setScale:1.0f];
        }
        CGAffineTransform transform = CGAffineTransformMakeScale([recognizer scale],  [recognizer scale]);
        imgView.transform = transform;
    }
}
person Shefali Soni    schedule 27.09.2011
comment
Это отличное решение :). Спасибо. - person sabiland; 24.06.2017

Имейте в виду, что вы НИКОГДА не увеличиваете UIImage. КОГДА-ЛИБО.

Вместо этого вы увеличиваете и уменьшаете масштаб view, на котором отображается UIImage.

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

Во всех случаях вам необходимо реализовать touchesBegan, touchesMoved и т.п., чтобы определить, что пользователь пытается сделать (масштабирование, панорамирование и т. Д.).

person August    schedule 01.02.2009
comment
+1 за пояснение, никогда не думал об этом так, радуется, чувак - person Elmo; 07.11.2011
comment
@August, можете ли вы предоставить мне какой-либо пример масштабирования и поворота изображения на touchBegan, touchMoved? - person Mitesh Dobareeya; 25.04.2016

Вот решение, которое я использовал раньше, для которого не требуется использовать UIWebView.

- (UIImage *)scaleAndRotateImage(UIImage *)image
{
    int kMaxResolution = 320; // Or whatever

    CGImageRef imgRef = image.CGImage;

    CGFloat width = CGImageGetWidth(imgRef);
    CGFloat height = CGImageGetHeight(imgRef);


    CGAffineTransform transform = CGAffineTransformIdentity;
    CGRect bounds = CGRectMake(0, 0, width, height);
    if (width > kMaxResolution || height > kMaxResolution) {
        CGFloat ratio = width/height;
        if (ratio > 1) {
            bounds.size.width = kMaxResolution;
            bounds.size.height = bounds.size.width / ratio;
        }
        else {
            bounds.size.height = kMaxResolution;
            bounds.size.width = bounds.size.height * ratio;
        }
    }

    CGFloat scaleRatio = bounds.size.width / width;
    CGSize imageSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef));
    CGFloat boundHeight;
    UIImageOrientation orient = image.imageOrientation;
    switch(orient) {

        case UIImageOrientationUp: //EXIF = 1
            transform = CGAffineTransformIdentity;
            break;

        case UIImageOrientationUpMirrored: //EXIF = 2
            transform = CGAffineTransformMakeTranslation(imageSize.width, 0.0);
            transform = CGAffineTransformScale(transform, -1.0, 1.0);
            break;

        case UIImageOrientationDown: //EXIF = 3
            transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);
            transform = CGAffineTransformRotate(transform, M_PI);
            break;

        case UIImageOrientationDownMirrored: //EXIF = 4
            transform = CGAffineTransformMakeTranslation(0.0, imageSize.height);
            transform = CGAffineTransformScale(transform, 1.0, -1.0);
            break;

        case UIImageOrientationLeftMirrored: //EXIF = 5
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.width);
            transform = CGAffineTransformScale(transform, -1.0, 1.0);
            transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
            break;

        case UIImageOrientationLeft: //EXIF = 6
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeTranslation(0.0, imageSize.width);
            transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
            break;

        case UIImageOrientationRightMirrored: //EXIF = 7
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeScale(-1.0, 1.0);
            transform = CGAffineTransformRotate(transform, M_PI / 2.0);
            break;

        case UIImageOrientationRight: //EXIF = 8
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeTranslation(imageSize.height, 0.0);
            transform = CGAffineTransformRotate(transform, M_PI / 2.0);
            break;

        default:
            [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"];

    }

    UIGraphicsBeginImageContext(bounds.size);

    CGContextRef context = UIGraphicsGetCurrentContext();

    if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) {
        CGContextScaleCTM(context, -scaleRatio, scaleRatio);
        CGContextTranslateCTM(context, -height, 0);
    }
    else {
        CGContextScaleCTM(context, scaleRatio, -scaleRatio);
        CGContextTranslateCTM(context, 0, -height);
    }

    CGContextConcatCTM(context, transform);

    CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);
    UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return imageCopy;
}

Статью можно найти в службе поддержки Apple по адресу: http://discussions.apple.com/message.jspa?messageID=7276709#7276709

person Niels Hansen    schedule 01.02.2009
comment
-1 для страницы поддержки, размещенной на jsp. пожимает кулаком при синтаксисе точки - person esharp; 18.11.2014
comment
Не могли бы вы рассказать мне, как вызвать этот метод (при движении или прикосновении мыши)? - person Bhumesh Purohit; 17.04.2017

Ответы Шафали и JRV были расширены, чтобы включить панорамирование и масштабирование:

#define MINIMUM_SCALE 0.5
#define MAXIMUM_SCALE 6.0
@property CGPoint translation;


- (void)pan:(UIPanGestureRecognizer *)gesture {
    static CGPoint currentTranslation;
    static CGFloat currentScale = 0;
    if (gesture.state == UIGestureRecognizerStateBegan) {
        currentTranslation = _translation;
        currentScale = self.view.frame.size.width / self.view.bounds.size.width;
    }
    if (gesture.state == UIGestureRecognizerStateEnded || gesture.state == UIGestureRecognizerStateChanged) {

        CGPoint translation = [gesture translationInView:self.view];

        _translation.x = translation.x + currentTranslation.x;
        _translation.y = translation.y + currentTranslation.y;
        CGAffineTransform transform1 = CGAffineTransformMakeTranslation(_translation.x , _translation.y);
        CGAffineTransform transform2 = CGAffineTransformMakeScale(currentScale, currentScale);
        CGAffineTransform transform = CGAffineTransformConcat(transform1, transform2);
        self.view.transform = transform;
    }
}


- (void)pinch:(UIPinchGestureRecognizer *)gesture {
    if (gesture.state == UIGestureRecognizerStateEnded || gesture.state == UIGestureRecognizerStateChanged) {
//        NSLog(@"gesture.scale = %f", gesture.scale);

        CGFloat currentScale = self.view.frame.size.width / self.view.bounds.size.width;
        CGFloat newScale = currentScale * gesture.scale;

        if (newScale < MINIMUM_SCALE) {
            newScale = MINIMUM_SCALE;
        }
        if (newScale > MAXIMUM_SCALE) {
            newScale = MAXIMUM_SCALE;
        }

        CGAffineTransform transform1 = CGAffineTransformMakeTranslation(_translation.x, _translation.y);
        CGAffineTransform transform2 = CGAffineTransformMakeScale(newScale, newScale);
        CGAffineTransform transform = CGAffineTransformConcat(transform1, transform2);
        self.view.transform = transform;
        gesture.scale = 1;
    }
}
person Paul King    schedule 22.07.2015
comment
пожалуйста, не упоминайте ответ других, поскольку они могут удалить свой ответ в любое время. - person Enamul Hassan; 22.07.2015

Самый простой способ сделать это, если все, что вам нужно, - это масштабирование щипком, - это поместить ваше изображение в UIWebView (напишите небольшой объем кода оболочки html, сделайте ссылку на свое изображение, и вы в основном закончили). Более сложный способ сделать это - использовать touchesBegan, touchesMoved и touchesEnded для отслеживания пальцев пользователя и соответствующим образом настроить свойство преобразования вашего представления.

person Ben Gottlieb    schedule 01.02.2009
comment
Можете ли вы предложить мне какой-либо пример, связанный с вашим ответом. Как увеличить и повернуть изображение с помощью методов touchesBegan, touchesMoved. Ссылка на мой вопрос = ›stackoverflow.com/questions/36833841/ - person Mitesh Dobareeya; 25.04.2016

Имейте в виду, что вы не хотите увеличивать / уменьшать масштаб UIImage. Вместо этого попробуйте увеличить / уменьшить масштаб представления, который содержит контроллер представления UIImage.

Я решил эту проблему. Взгляните на мой код:

@IBAction func scaleImage(sender: UIPinchGestureRecognizer) {
        self.view.transform = CGAffineTransformScale(self.view.transform, sender.scale, sender.scale)
        sender.scale = 1
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        view.backgroundColor = UIColor.blackColor()
    }

Примечание: не забудьте подключить PinchGestureRecognizer.

person G A    schedule 17.08.2016