web-dev-qa-db-fra.com

Étirer un UIImage tout en préservant les coins

J'essaie d'étirer une image de flèche de navigation tout en préservant les bords afin que les étirements du milieu et les extrémités soient fixes.

Voici l'image que j'essaie d'étirer:

enter image description here

Le code iOS 5 suivant permet à l'image lorsqu'elle est redimensionnée d'étirer les parties centrales de l'image définies par les UIEdgeInsets.

[[UIImage imageNamed:@"arrow.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(15, 7, 15, 15)];

Il en résulte une image qui ressemble à ceci (si le cadre de l'image est défini sur 70 pixels de large):

enter image description here

C'est en fait ce que je veux, mais resizableImageWithCapInsets n'est pris en charge que sur iOS 5 et versions ultérieures.

Avant iOS 5, la seule méthode similaire est stretchableImageWithLeftCapWidth: topCapHeight mais vous ne pouvez spécifier que les encarts supérieur et gauche, ce qui signifie que l'image doit avoir des bords de forme égale.

Existe-t-il une façon iOS 4 de redimensionner l'image de la même manière que la méthode resizableImageWithCapInsets d'iOS 5, ou une autre façon de procéder?

27
Camsoft

Votre hypothèse ici est fausse:

Avant iOS 5, la seule méthode similaire est extensibleImageWithLeftCapWidth: topCapHeight mais vous ne pouvez spécifier que les encarts supérieur et gauche , ce qui signifie que l'image doit avoir des bords de forme égale.

Les capuchons sont définis comme suit - je vais parcourir le capuchon gauche, mais le même principe s'applique au capuchon supérieur.

Supposons que votre image mesure 20 pixels de large.

  • Largeur du capuchon gauche - il s'agit de la partie du côté gauche de l'image qui ne peut pas être étirée. Dans la méthode stretchableImage, vous envoyez une valeur de 10 pour cela.
  • Partie extensible - elle est supposée avoir une largeur d'un pixel, ce seront donc les pixels de la colonne "11", faute d'une meilleure description
  • Cela signifie qu'il y a un plafond droit implicite des 9 pixels restants de votre image - cela ne sera pas non plus déformé.

Ceci est tiré de la documentation

leftCapWidth

Les extrémités définissent la partie d'une image qui ne doit pas être redimensionnée lorsqu'une image est étirée. Cette technique est utilisée pour implémenter des boutons et d'autres éléments d'interface basés sur l'image redimensionnables. Lorsqu'un bouton avec des capuchons d'extrémité est redimensionné, le redimensionnement se produit uniquement au milieu du bouton, dans la zone située entre les capuchons d'extrémité. Les embouts eux-mêmes conservent leur taille et leur apparence d'origine.

Cette propriété spécifie la taille de l'embout gauche. La partie centrale (étirable) est supposée avoir une largeur de 1 pixel. Le capuchon d'extrémité droit est donc calculé en ajoutant la taille du capuchon d'extrémité gauche et la partie médiane ensemble, puis en soustrayant cette valeur de la largeur de l'image:

rightCapWidth = image.size.width - (image.leftCapWidth + 1);

31
jrturton
UIImage *image = [UIImage imageNamed:@"img_loginButton.png"];
    UIEdgeInsets edgeInsets;
    edgeInsets.left = 0.0f;
    edgeInsets.top = 0.0f;
    edgeInsets.right = 5.0f; //Assume 5px will be the constant portion in your image
    edgeInsets.bottom = 0.0f;
    image = [image resizableImageWithCapInsets:edgeInsets];
//Use this image as your controls image
9
Vicky

Votre exemple est parfaitement possible en utilisant stretchableImageWithLeftCapWidth:topCapHeight: avec un plafond gauche de 15 (apparemment, à la lecture de votre code). Cela va étirer horizontalement le bouton en répétant la colonne du milieu.

5
Steven Kramer

Vous pouvez étendre UIImage pour permettre d'étirer une image avec une protection Edge personnalisée (étirant ainsi l'intérieur de l'image, au lieu de la recouvrir):

UIImage + utils.h:

#import <UIKit/UIKit.h>
@interface UIImage(util_extensions)
//extract a portion of an UIImage instance 
-(UIImage *) cutout: (CGRect) coords;
//create a stretchable rendition of an UIImage instance, protecting edges as specified in cornerCaps
-(UIImage *) stretchImageWithCapInsets: (UIEdgeInsets) cornerCaps toSize: (CGSize) size;
@end

UIImage + utils.m:

#import "UIImage+utils.h"
@implementation UIImage(util_extensions)
-(UIImage *) cutout: (CGRect) coords {
    UIGraphicsBeginImageContext(coords.size);
    [self drawAtPoint: CGPointMake(-coords.Origin.x, -coords.Origin.y)];
    UIImage *rslt = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return rslt;
}

-(UIImage *) stretchImageWithCapInsets: (UIEdgeInsets) cornerCaps toSize: (CGSize) size { 
    UIGraphicsBeginImageContext(size);

    [[self cutout: CGRectMake(0,0,cornerCaps.left,cornerCaps.top)] drawAtPoint: CGPointMake(0,0)]; //topleft
    [[self cutout: CGRectMake(self.size.width-cornerCaps.right,0,cornerCaps.right,cornerCaps.top)] drawAtPoint: CGPointMake(size.width-cornerCaps.right,0)]; //topright
    [[self cutout: CGRectMake(0,self.size.height-cornerCaps.bottom,cornerCaps.left,cornerCaps.bottom)] drawAtPoint: CGPointMake(0,size.height-cornerCaps.bottom)]; //bottomleft
    [[self cutout: CGRectMake(self.size.width-cornerCaps.right,self.size.height-cornerCaps.bottom,cornerCaps.right,cornerCaps.bottom)] drawAtPoint: CGPointMake(size.width-cornerCaps.right,size.height-cornerCaps.bottom)]; //bottomright

    [[self cutout: CGRectMake(cornerCaps.left,0,self.size.width-cornerCaps.left-cornerCaps.right,cornerCaps.top)]
 drawInRect: CGRectMake(cornerCaps.left,0,size.width-cornerCaps.left-cornerCaps.right,cornerCaps.top)]; //top

    [[self cutout: CGRectMake(0,cornerCaps.top,cornerCaps.left,self.size.height-cornerCaps.top-cornerCaps.bottom)]
 drawInRect: CGRectMake(0,cornerCaps.top,cornerCaps.left,size.height-cornerCaps.top-cornerCaps.bottom)]; //left

    [[self cutout: CGRectMake(cornerCaps.left,self.size.height-cornerCaps.bottom,self.size.width-cornerCaps.left-cornerCaps.right,cornerCaps.bottom)]
 drawInRect: CGRectMake(cornerCaps.left,size.height-cornerCaps.bottom,size.width-cornerCaps.left-cornerCaps.right,cornerCaps.bottom)]; //bottom

    [[self cutout: CGRectMake(self.size.width-cornerCaps.right,cornerCaps.top,cornerCaps.right,self.size.height-cornerCaps.top-cornerCaps.bottom)]
 drawInRect: CGRectMake(size.width-cornerCaps.right,cornerCaps.top,cornerCaps.right,size.height-cornerCaps.top-cornerCaps.bottom)]; //right

    [[self cutout: CGRectMake(cornerCaps.left,cornerCaps.top,self.size.width-cornerCaps.left-cornerCaps.right,self.size.height-cornerCaps.top-cornerCaps.bottom)]
 drawInRect: CGRectMake(cornerCaps.left,cornerCaps.top,size.width-cornerCaps.left-cornerCaps.right,size.height-cornerCaps.top-cornerCaps.bottom)]; //interior

    UIImage *rslt = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return [rslt resizableImageWithCapInsets: cornerCaps];
}

@end
4
Mark Stasak

Version Swift 3.0 de la réponse de Vicky.

var imageInset:UIEdgeInsets = UIEdgeInsets()
        imageInset.left = 10.0
        imageInset.top = 10.0
        imageInset.bottom = 10.0
        imageInset.right = 10.0
        self.myImageView.image = myimage.resizableImage(withCapInsets: imageInset)
2
shesh nath