Wie kann ich ein UIImage-Objekt vergrößern / verkleinern, wenn der Benutzer den Bildschirm einklemmt?

83

Ich möchte ein UIImage-Objekt vergrößern / verkleinern, wenn der Benutzer die Standard-Pinch-Aktion für meine Anwendung ausführt. Ich verwende derzeit eine UIImageView, um mein Bild anzuzeigen, wenn dieses Detail in irgendeiner Weise hilfreich ist.

Ich versuche herauszufinden, wie das geht, aber bisher kein solches Glück.

Irgendwelche Hinweise?

jpm
quelle

Antworten:

85

Eine andere einfache Möglichkeit, dies zu tun, besteht darin, Ihre UIImageViewinnerhalb eines zu platzieren UIScrollView. Wie hier beschrieben , müssen Sie die Inhaltsgröße der Bildlaufansicht so einstellen, dass sie Ihrer UIImageView'sGröße entspricht. Stellen Sie Ihre Controller-Instanz als Delegaten der Bildlaufansicht ein und implementieren Sie die Methoden viewForZoomingInScrollView:und scrollViewDidEndZooming:withView:atScale:, um das Zoomen und Schwenken von Bildern zu ermöglichen. Dies ist effektiv die Lösung von Ben, nur auf eine etwas leichtere Art und Weise, da Sie nicht den Overhead einer vollständigen Webansicht haben.

Ein Problem, auf das Sie möglicherweise stoßen, besteht darin, dass die Skalierung in der Bildlaufansicht in Form von Transformationen erfolgt, die auf das Bild angewendet werden. Dies kann bei hohen Zoomfaktoren zu Unschärfe führen. Für etwas, das neu gezeichnet werden kann, können Sie meinen Vorschlägen hier folgen , um nach Abschluss der Kneifgeste eine schärfere Anzeige zu erhalten. Zu diesem Zeitpunkt kann die Lösung von hniels verwendet werden, um Ihr Bild neu zu skalieren.

Brad Larson
quelle
2
Stellen Sie sicher, dass Sie MaximumZoomScale und / oder MinimumZoomScale ändern :).
Chris Prince
93

Wie bereits beschrieben, besteht die einfachste Lösung darin, Ihre UIImageView in eine UIScrollView zu integrieren. Ich habe dies in der .xib-Datei des Interface Builder getan.

Legen Sie in viewDidLoad die folgenden Variablen fest. Stellen Sie Ihren Controller als UIScrollViewDelegate ein.

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

Sie müssen die folgende Methode implementieren, um die Bildansicht zurückzugeben, die Sie zoomen möchten.

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

In Versionen vor iOS9 müssen Sie möglicherweise auch diese leere Delegatenmethode hinzufügen:

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

In der Apple-Dokumentation wird gut beschrieben, wie das geht:

Schurke
quelle
2
Es ist in Ordnung, scrollViewDidEndZooming zu löschen: withView: Jetzt habe ich mit iOS9 Xcode7
ElonChan
1
Für mich geht das! Ohne Implementierungsmethode scrollViewDidEndZooming :.
Johnny Zhang
48

Shefalis Lösung für UIImageView funktioniert hervorragend, muss jedoch ein wenig geändert werden:

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

(Shefalis Lösung hatte den Nachteil, dass sie beim Kneifen nicht kontinuierlich skaliert wurde. Außerdem wurde beim Starten einer neuen Prise die aktuelle Bildskalierung zurückgesetzt.)

JRV
quelle
Ich möchte die Pan-Geste aktivieren, nachdem die Pinch-Geste gestartet wurde. Wie geht das?
Gajendra K Chauhan
@ Gajendra: In diesem Fall sollten Sie Ihre Komponenten in eine Bildlaufansicht einbetten, die beide
sofort
Ich möchte jedoch Funktionen sowohl für die Tap-Geste als auch für die Pinch-Geste. Ich habe auch Gitter (Ebenen) in Imageview verwendet. Darf ich wissen, ob es möglich ist, in der Bildlaufansicht eine Pinch-Geste und eine Tap-Geste zu verwenden.
Gajendra K Chauhan
@GajendraKChauhan: Eine Bildlaufansicht unterstützt das Zoomen und Schwenken aus der Box heraus. Denken Sie daran, die minimale / maximale Zoomskala festzulegen, aber sehen Sie sich auch die Antwort von Brad Larsons an. Und wenn Sie auch auf eine Geste tippen möchten, können Sie diese als Geste hinzufügen.
JRV
@JRV, welche Delegaten muss ich hinzufügen, damit die self.frame.size.width erkannt wird?
23

Der folgende Code hilft beim Zoomen von UIImageView ohne Verwendung von 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;
    }
}
Shefali Soni
quelle
Dies ist die höchste Lösung :). Vielen Dank.
Sabiland
19

Denken Sie daran, dass Sie NIEMALS einen vergrößern UIImage. JE.

Stattdessen zoomen Sie in das hinein und heraus, das viewdas anzeigt UIImage.

In diesem speziellen Fall können Sie eine benutzerdefinierte UIViewZeichnung mit benutzerdefinierter Zeichnung erstellen , um das Bild anzuzeigen, eine, UIImageViewdie das Bild für Sie anzeigt, oder eine, UIWebViewdie zusätzlichen HTML- Code zum Sichern benötigt.

In allen Fällen müssen Sie implementieren touchesBegan, touchesMovedund dergleichen , um zu bestimmen , was der Benutzer versucht , zu tun (Zoom, Pan, etc.).

August
quelle
+1 zur Klarstellung, nie so gedacht, Prost Typ
Elmo
@August, kannst du mir ein Beispiel geben, welches Bild bei TouchesBegan, TastsMoved zoomen und drehen?
Mitesh Dobareeya
7

Hier ist eine Lösung, die ich zuvor verwendet habe und für die Sie UIWebView nicht verwenden müssen.

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

Der Artikel ist im Apple Support unter folgender Adresse verfügbar: http://discussions.apple.com/message.jspa?messageID=7276709#7276709

Niels Hansen
quelle
-1 für eine von JSP gehostete Support-Seite. schüttelt die Faust bei der
Punktsyntax
Können Sie mir bitte mitteilen, wie ich diese Methode aufrufen soll (bei Mausbewegung oder Berührung)?
Bhumesh Purohit
5

Die Antworten von Shafali und JRV wurden um Schwenken und Drücken zum Zoomen erweitert:

#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;
    }
}
Paul King
quelle
Bitte vermeiden Sie es, die Antwort anderer zu erwähnen, da diese ihre Antwort jederzeit entfernen können.
Enamul Hassan
3

Der einfachste Weg, dies zu tun, wenn Sie nur ein wenig zoomen möchten, besteht darin, Ihr Bild in einem zu platzieren UIWebView(schreiben Sie eine kleine Menge HTML-Wrapper-Code, verweisen Sie auf Ihr Bild, und Sie sind im Grunde fertig). Der kompliziertere Weg, dies zu tun, besteht darin touchesBegan, die Finger des Benutzers zu verwenden touchesMovedund touchesEndedzu verfolgen und die Transformationseigenschaft Ihrer Ansicht entsprechend anzupassen.

Ben Gottlieb
quelle
Kannst du mir ein Beispiel für deine Antwort vorschlagen? Wie kann ich ein Bild mit den Methoden touchBegan, touchMoved zoomen und drehen? Meine Frage link => stackoverflow.com/questions/36833841/…
Mitesh Dobareeya
0

Denken Sie daran, dass Sie UIImage nicht vergrößern oder verkleinern möchten. Versuchen Sie stattdessen, die Ansicht, die den UIImage View Controller enthält, zu vergrößern / zu verkleinern.

Ich habe eine Lösung für dieses Problem gefunden. Schauen Sie sich meinen Code an:

@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: Vergessen Sie nicht, den PinchGestureRecognizer anzuschließen.

G Azam
quelle