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

84

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

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

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

jpm
источник

Ответы:

85

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

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

Брэд Ларсон
источник
2
Убедитесь, что вы изменили maximumZoomScale и / или minimumZoomScale :).
Крис Принс
94

Как описывали другие, самое простое решение - поместить ваш 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 , документация делает хорошую работу по описанию , как это сделать:

Разбойник
источник
3
Можно удалить scrollViewDidEndZooming: withView: теперь я протестировал с iOS9 Xcode7
ElonChan
1
Меня устраивает! Без реализации scrollViewDidEndZooming :метода.
Джонни Чжан
48

Решение Шефали для 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;
    }
}

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

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

Приведенный ниже код помогает увеличить 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;
    }
}
Шефали Сони
источник
Это отличное решение :). Спасибо.
sabiland
19

Имейте в виду, что вы НИКОГДА не увеличиваете масштаб изображения UIImage. КОГДА-ЛИБО.

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

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

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

Август
источник
+1 для пояснения, никогда не думал об этом так, радуется, чувак
Элмо
@ Август, можете ли вы предоставить мне какой-либо пример масштабирования и поворота изображения на touchBegan, touchMoved?
Mitesh Dobareeya
7

Вот решение, которое я использовал раньше, для которого не требуется использовать 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.

Нильс Хансен
источник
-1 для страницы поддержки, размещенной на jsp. качает кулаком синтаксис с точкой
esharp
Не могли бы вы рассказать мне, как вызвать этот метод (при движении или прикосновении мыши)?
Bhumesh Purohit
5

Ответы Шафали и 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;
    }
}
Пол Кинг
источник
пожалуйста, не упоминайте ответ других, поскольку они могут удалить свой ответ в любое время.
Enamul Hassan
3

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

Бен Готтлиб
источник
Можете ли вы предложить мне любой пример, связанный с вашим ответом. Как увеличить и повернуть изображение с помощью методов touchesBegan, touchesMoved. Ссылка на мой вопрос => stackoverflow.com/questions/36833841/…
Mitesh Dobareeya
0

Имейте в виду, что вы не хотите увеличивать / уменьшать масштаб 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()
    }

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

G Azam
источник