Come ingrandire / ridurre un oggetto UIImage quando l'utente pizzica lo schermo?


84

Vorrei ingrandire / ridurre un oggetto UIImage quando l'utente esegue l'azione di pizzicamento standard sulla mia applicazione. Attualmente sto usando un UIImageView per visualizzare la mia immagine, se quel dettaglio aiuta in qualche modo.

Sto cercando di capire come farlo, ma finora non ho avuto fortuna.

Qualche indizio?

Risposte:


85

Un altro modo semplice per farlo è quello di inserire il vostro UIImageViewall'interno di una UIScrollView. Come descrivo qui , devi impostare contentSize della visualizzazione a scorrimento in modo che corrisponda alla tua UIImageView'sdimensione. Imposta l'istanza del controller in modo che sia il delegato della visualizzazione a scorrimento e implementa i metodi viewForZoomingInScrollView:e scrollViewDidEndZooming:withView:atScale:per consentire lo zoom e la panoramica delle immagini. Questo è effettivamente ciò che fa la soluzione di Ben, solo in un modo leggermente più leggero, poiché non hai il sovraccarico di una visualizzazione web completa.

Un problema che potresti incontrare è che il ridimensionamento all'interno della visualizzazione a scorrimento si presenta sotto forma di trasformazioni applicate all'immagine. Ciò può causare sfocatura con fattori di zoom elevati. Per qualcosa che può essere ridisegnato, puoi seguire i miei suggerimenti qui per fornire una visualizzazione più nitida dopo che il gesto di pizzicamento è terminato. La soluzione di hniels potrebbe essere utilizzata a quel punto per ridimensionare la tua immagine.


2
Assicurati di cambiare maximumZoomScale e / o minimumZoomScale :).
Chris Prince

94

Come altri descritti, la soluzione più semplice è mettere il tuo UIImageView in un UIScrollView. L'ho fatto nel file .xib di Interface Builder.

In viewDidLoad, impostare le seguenti variabili. Imposta il controller in modo che sia un 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;
}

È necessario implementare il seguente metodo per restituire l'immagine che si desidera ingrandire.

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

Nelle versioni precedenti a iOS9, potrebbe essere necessario aggiungere anche questo metodo delegato vuoto:

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

La documentazione di Apple fa un buon lavoro nel descrivere come eseguire questa operazione:


3
Va bene eliminare scrollViewDidEndZooming: withView: ora, ho provato con iOS9 Xcode7
ElonChan

1
Per me funziona! Senza implementare il scrollViewDidEndZooming :metodo.
Johnny Zhang

48

La soluzione di Shefali per UIImageView funziona alla grande, ma necessita di una piccola modifica:

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

(La soluzione di Shefali aveva lo svantaggio di non ridimensionarsi continuamente durante la presa. Inoltre, quando si avviava una nuova presa, la scala dell'immagine corrente veniva ripristinata.)


Desidero abilitare il gesto di panoramica dopo l'avvio del gesto di pizzicamento. Come si fa?
Gajendra K Chauhan

@ Gajendra: In questo caso, penso che dovresti usare incorporare i tuoi componenti in una visualizzazione a scorrimento, che supporta entrambi
immediatamente

Ma voglio funzionalità sia per il gesto di tocco che per il gesto di pizzico. Ho anche usato la griglia (livelli) su Imageview. Posso sapere, è possibile utilizzare il gesto di pizzicare e toccare il gesto nella visualizzazione a scorrimento.?
Gajendra K Chauhan

@GajendraKChauhan: una visualizzazione a scorrimento supporta il pizzico per ingrandire e la panoramica fuori dalla scatola - ricorda solo di impostare la scala di zoom minima / massima, ma guarda anche la risposta di Brad Larsons. E se vuoi anche toccare il gesto, puoi aggiungerlo come gesto.
JRV

@JRV, quali delegati devo aggiungere per far riconoscere self.frame.size.width?

23

Il codice seguente aiuta a ingrandire UIImageView senza utilizzare 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;
    }
}

Questa è la soluzione suprema :). Grazie.
sabiland

19

Tieni presente che non stai MAI ingrandendo su un file UIImage. MAI.

Invece, stai ingrandendo e viewrimpicciolendo il file UIImage.

In questo caso particolare, potresti scegliere di creare un UIViewdisegno personalizzato con un disegno personalizzato per visualizzare l'immagine, un UIImageViewche mostra l'immagine per te o un UIWebViewche avrà bisogno di HTML aggiuntivo per il backup.

In tutti i casi, sarà necessario implementare touchesBegan, touchesMovede simili per determinare ciò che l'utente sta cercando di fare (zoom, panoramica, ecc.).


+1 per chiarimenti, mai pensato in questo modo, applausi amico
Elmo

@ August, puoi fornirmi un esempio di zoom e rotazione dell'immagine su touchesBegan, touchesMoved?
Mitesh Dobareeya

7

Ecco una soluzione che ho usato prima che non richiede l'utilizzo di 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;
}

L'articolo è disponibile sul supporto Apple all'indirizzo: http://discussions.apple.com/message.jspa?messageID=7276709#7276709


-1 per una pagina di supporto ospitata da jsp. scuote il pugno alla sintassi del punto
esharp

Puoi fornirmi come chiamare questo metodo (con il movimento del mouse o con il tocco)?
Bhumesh Purohit

5

Le risposte di Shafali e JRV si sono estese per includere panning e pizzica per ingrandire:

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

si prega di evitare di menzionare la risposta di altri in quanto possono rimuovere la loro risposta in qualsiasi momento.
Enamul Hassan

3

Il modo più semplice per farlo, se tutto ciò che vuoi è zoomare con le dita, è posizionare la tua immagine all'interno di un UIWebView(scrivi una piccola quantità di codice html wrapper, fai riferimento alla tua immagine e il gioco è fatto). Il modo più completo per farlo è usare touchesBegan, touchesMovede touchesEndedtenere traccia delle dita dell'utente e regolare la proprietà di trasformazione della vista in modo appropriato.


puoi suggerirmi qualche esempio relativo alla tua risposta. Come posso ingrandire e ruotare l'immagine usando i metodi touchesBegan, touchesMoved. Il mio collegamento di domanda => stackoverflow.com/questions/36833841/...
Mitesh Dobareeya

0

Tieni presente che non vuoi ingrandire / rimpicciolire UIImage. Prova invece ad ingrandire / ridurre la vista che contiene il controller di visualizzazione UIImage.

Ho trovato una soluzione per questo problema. Dai un'occhiata al mio codice:

@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: non dimenticare di collegare PinchGestureRecognizer.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.