web-dev-qa-db-fra.com

Comment faire un zoom avant/arrière sur un objet UIImage lorsque l'utilisateur pince l'écran

Je souhaite effectuer un zoom avant/arrière sur un objet UIImage lorsque l'utilisateur effectue l'action de pincement standard sur mon application. J'utilise actuellement un UIImageView pour afficher mon image, si ce détail peut l'aider de quelque manière que ce soit.

J'essaie de comprendre comment faire cela, mais aucune chance de la sorte jusqu'à présent.

Des indices?

78
jpm

Une autre façon simple de procéder consiste à placer votre UIImageView dans une UIScrollView. Comme je le décris ici , vous devez définir le contenu contentSize de la vue de défilement de sorte qu'il soit identique à votre taille UIImageView's. Définissez votre instance de contrôleur pour être le délégué de la vue de défilement et implémentez les méthodes viewForZoomingInScrollView: et scrollViewDidEndZooming:withView:atScale: pour permettre le zoom par pincement et le panoramique de l'image. C’est effectivement ce que fait la solution de Ben, mais de manière légèrement plus légère, car vous n’avez pas l’impression superficielle d’une vue Web complète.

Un problème que vous pouvez rencontrer est que la mise à l'échelle dans la vue de défilement se présente sous la forme de transformations appliquées à l'image. Cela peut entraîner un flou dû à des facteurs de zoom élevés. Pour quelque chose qui peut être redessiné, vous pouvez suivre mes suggestions ici pour fournir un affichage plus net une fois le geste de pincement terminé. La solution de hniels pourrait alors être utilisée pour redimensionner votre image.

83
Brad Larson

Comme d'autres l'ont décrit, la solution la plus simple consiste à placer votre UIImageView dans un UIScrollView. Je l'ai fait dans le fichier .xib d'Interface Builder.

Dans viewDidLoad, définissez les variables suivantes. Définissez votre contrôleur pour qu’il soit 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;
}

Vous devez implémenter la méthode suivante pour renvoyer l'image que vous souhaitez agrandir.

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

Dans les versions antérieures à iOS9, vous devrez peut-être également ajouter cette méthode de délégation vide:

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

La Documentation Apple décrit bien comment procéder:

88
rogue

La solution de Shefali pour UIImageView fonctionne très bien, mais elle nécessite quelques modifications:

- (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 solution de Shefali présentait l'inconvénient de ne pas se redimensionner continuellement lors du pincement. De plus, lors du démarrage d'un nouveau pincement, l'échelle de l'image actuelle était réinitialisée.)

47
JRV

Le code ci-dessous permet de zoomer sur UIImageView sans utiliser 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;
    }
}
23
Shefali Soni

Gardez à l'esprit que vous ne zoomez JAMAIS sur une UIImage. DÉJÀ.

Au lieu de cela, vous effectuez un zoom avant et arrière sur la view qui affiche la UIImage.

Dans ce cas particulier, vous pouvez choisir de créer une UIView personnalisée avec un dessin personnalisé pour afficher l'image, une UIImageView qui affiche l'image pour vous ou une UIWebView qui nécessitera du code HTML supplémentaire pour la sauvegarder.

Dans tous les cas, vous devrez implémenter touchesBegan, touchesMoved, etc., pour déterminer ce que l'utilisateur tente de faire (zoom, panoramique, etc.).

19
August

Voici une solution que j'ai déjà utilisée et qui ne nécessite pas l'utilisation de 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;
}

Vous trouverez cet article sur le support Apple à l'adresse suivante: http://discussions.Apple.com/message.jspa?messageID=7276709#7276709

8
Niels Hansen

Les réponses de Shafali et JRV ont été étendues pour inclure le panoramique et le pincement pour zoomer:

#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;
    }
}
5
paul king

Le moyen le plus simple de le faire, si tout ce que vous voulez, est de zoomer par pincement, consiste à placer votre image dans une variable UIWebView (écrivez une petite quantité de code html, faites référence à votre image et vous avez pratiquement terminé). La manière la plus simple de le faire est d'utiliser touchesBegan, touchesMoved et touchesEnded pour garder la trace des doigts de l'utilisateur et ajuster la propriété de transformation de votre vue de manière appropriée.

3
Ben Gottlieb

Gardez à l'esprit que vous ne voulez pas zoomer/dézoomer UIImage. Essayez plutôt d’agrandir ou de réduire la vue qui contient le contrôleur de vue UIImage.

J'ai fait une solution à ce problème. Regardez mon code:

@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: N'oubliez pas de brancher le PinchGestureRecognizer.

0
G Azam