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


84

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

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

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

Ответы:


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

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


Я хочу, чтобы жест панорамирования был включен после запуска жеста сжатия. Как это сделать?
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.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.