33 votes

Utilisation d'images extensibles dans les storyboards Xcode

J'utilise des storyboards pour mettre en page mes contrôleurs de vue et j'aimerais utiliser des images extensibles pour mes boutons (afin de ne pas avoir à générer plusieurs images de tailles différentes).

Est-il possible de le faire directement dans les storyboards sans écrire de code ? J'aime beaucoup la possibilité d'utiliser les storyboards pour tous les éléments graphiques et de garder le code propre des éléments de l'interface utilisateur, mais il semble que je ne puisse pas le faire ici.

Si ce n'est pas possible, que suggéreriez-vous d'autre ?

74voto

Michael G. Emmons Points 16681

Mise à jour pour iOS 7+.
iOS 7+ prend désormais en charge les images extensibles de manière native via le catalogue d'actifs. À l'aide du catalogue d'actifs, vous pouvez désormais spécifier la façon dont les images sont découpées en tranches et leur mise à l'échelle (étirement ou tuile). Ces attributs du catalogue d'actifs pour l'image seront immédiatement reflétés dans le storyboard. Une nouvelle amélioration importante. Pour plus d'informations, voir Documents d'Apple sur l'Asset Catalog

Pour le déploiement sur des versions d'iOS antérieures à 7 :
C'est un fait peu connu, mais vous pouvez tout à fait définir les inserts de cap d'une image en utilisant uniquement Interface Builder/Storyboard et les propriétés d'étirement de l'inspecteur d'attributs. Merci à Victor pour la réponse originale.

Si l'on regarde les propriétés d'étirement dans l'inspecteur des attributs d'un fichier UIImage les valeurs X et Y sont les positions du point de départ de l'étirement, par rapport à la largeur et à la hauteur totales de l'image. Une valeur de 0,5 correspond à un point situé au milieu de l'image.

La largeur et la hauteur sont les dimensions de la zone extensible par rapport à la taille de l'image. Ainsi, si vous attribuez à la largeur une valeur de 1 / imageWidth, la zone extensible aura une largeur de 1 pixel.

La plupart des images extensibles s'étireront à partir du milieu, donc l'utilisation de ces valeurs pour X, Y, largeur et hauteur fonctionnera généralement :

X = 0.5
Y = 0.5
Width = 1/imageWidth
Height = 1/imageHeight

Remarque : à moins que vous n'ayez une très petite image à étirer, cela signifie que les propriétés de largeur et de hauteur seront très petites (par exemple 0,008) et que 0,0 peut être utilisé à la place. Donc, en pratique, 0,5, 0,5, 0,0, 0,0 fonctionnera presque toujours pour X,Y, largeur et hauteur.

Dans le petit nombre de cas où 0,0 ne fonctionne pas pour la largeur et la hauteur, cela signifie que vous devez utiliser une calculatrice pour définir ces valeurs dans IB. Cependant, je pense que c'est généralement préférable à un réglage par programme, car vous pourrez voir l'image étirée résultante dans IB (WYSIWYG).

Stretchable image attributes

Mise à jour : Certaines personnes ont fait remarquer que bien que l'étirement des images fonctionne dans Storyboard en utilisant les suggestions ci-dessus, l'étirement des images sur les boutons est toujours cassé, même à partir de iOS7. Ne vous inquiétez pas, ce problème est facilement résolu en créant une fonction UIButton qui se charge de définir les inserts des capuchons pour les états de contrôle :

@implementation UIButton (Stretchable)

/* Automatically set cap insets for the background image. This assumes that
   the image is a standard slice size with a 1 px stretchable interior */
- (void)setBackgroundImageStretchableForState:(UIControlState)controlState
{
    UIImage *image = [self backgroundImageForState:controlState];
    if (image)
    {
       CGFloat capWidth =  floorf(image.size.width / 2);
       CGFloat capHeight =  floorf(image.size.height / 2);
       UIImage *capImage = [image resizableImageWithCapInsets:
                     UIEdgeInsetsMake(capHeight, capWidth, capHeight, capWidth)];

       [self setBackgroundImage:capImage forState:controlState];
    }
}

En utilisant cette catégorie, vous pouvez définir votre image extensible pour votre bouton via Storyboard et ensuite vous assurer facilement qu'elle s'étire correctement en appelant -setBackgroundImageStretchableForState: dans votre -viewDidLoad . L'itération dans la hiérarchie de votre vue rend cette opération triviale, même pour un grand nombre de boutons dans votre vue :

NSPredicate *predicate = 
    [NSPredicate predicateWithFormat:@"self isKindOfClass:%@",[UIButton class]];
NSArray *buttons = [self.view.subviews filteredArrayUsingPredicate:predicate];
for (UIButton *button in buttons)
   [button setBackgroundImageStretchableForState:UIControlStateNormal];

Bien que ce ne soit pas aussi bien que d'avoir une UIButton qui fait cela automatiquement pour vous (sous-classez UIButton n'est pas pratique puisqu'il s'agit d'un regroupement de classes), il vous donne presque la même fonctionnalité avec juste un peu de code passe-partout dans votre viewDidLoad -- vous pouvez définir toutes vos images de boutons dans Storyboard et les faire s'étirer correctement.

11voto

Lorenzo NEY Points 91

C'est faisable dans l'Interface Builder 5.0 de XCode avec le catalogue d'actifs. Créez un actif d'image ( si vous n'avez pas déjà un catalogue d'actifs, vous pouvez en créer un comme suit :

  1. File -> New -> File -> Resources -> Asset Catalog
  2. Puis Editor -> New Image Set
  3. Définissez les images pour chaque Idiom & Scale
  4. Ensuite, appuyez sur le bouton Show Slicing pour régler les tranches comme vous le souhaitez.

Consultez les documents d'Apple ici : Développeur Apple : Aide sur le catalogue des actifs Il ne vous reste plus qu'à définir l'image d'arrière-plan du bouton comme l'actif demandé.

EDIT : J'ai oublié de mentionner que cela fonctionne comme souhaité uniquement sous iOS7.

2voto

Philippe Sabourin Points 4957

Voici ce que j'ai fait : J'ai défini une prise pour le bouton et l'ai connectée, puis j'ai fait ceci dans viewDidLoad :

[self.someButton setBackgroundImage:[[self.someButton backgroundImageForState:UIControlStateNormal] resizableImageWithCapInsets:UIEdgeInsetsMake(3, 3, 4, 3)] forState:UIControlStateNormal];

Cela permet de réutiliser l'image que vous avez définie dans le storyboard, donc si vous la changez d'une couleur à une autre, cela fonctionnera, tant que les inserts ne changent pas.

Pour une vue qui avait beaucoup de ces choses, j'ai fait ça :

for (UIView * subview in self.view.subviews) {
        if ([subview isKindOfClass:[UIImageView class]] && subview.tag == 10) {
            UIImageView* textFieldImageBackground = (UIImageView*)subview;
            textFieldImageBackground.image = [textFieldImageBackground.image stretchableImageWithLeftCapWidth:7 topCapHeight:5];
        } else if([subview isKindOfClass:[UIButton  class]] && subview.tag == 11) {
            UIButton * button = (UIButton*)subview;
            [button setBackgroundImage:[[button backgroundImageForState:UIControlStateNormal] resizableImageWithCapInsets:UIEdgeInsetsMake(3, 3, 4, 3)] forState:UIControlStateNormal];
        }
    }

Notez que j'ai défini les balises pour tous ceux que je voulais étirer.

Je suis dans le même bateau que vous, cependant, j'aimerais être en mesure de définir ces choses très centrées sur l'interface utilisateur sur le storyboard lui-même.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X