web-dev-qa-db-fra.com

Comment charger une image dans prepareForInterfaceBuilder avec un IBDesignable UIImageView

Je souhaite charger un exemple d'image dans une variable UIImageView désignable de IB, à afficher dans Interface Builder lors de la modification de l'interface. Le code suivant ne fonctionne pas car l'espace réservé à la vue dans IB reste vide (la zone de vue contient uniquement le texte UIImageView):

@IBDesignable
class TestImageView : UIImageView
{
    override func prepareForInterfaceBuilder() {
        //let bundle = NSBundle.mainBundle()
        let bundle = NSBundle(forClass: nil)
        let imagePath = bundle.pathForResource("Test", ofType: "jpg")
        self.image = UIImage(contentsOfFile: imagePath)
    }
}

Notez que:

  • dans IB, la classe de classe personnalisée de la vue est correcte (TestImageView)
  • Test.jpg est présent dans le projet (si je définis manuellement la propriété image de la variable UIImageView dans IB, l'image s'affiche).
  • J'ai essayé les deux méthodes différentes pour obtenir le paquet présent dans le code

Ceci a été testé avec Xcode 6 beta 3.

Update : dans les deux cas, le chemin d'accès au paquet que je reçois est "/Applications/Temporary/Xcode6-Beta3.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Overlays". Dans ce chemin, l'image n'est évidemment pas présente.

23
mxb

Mis à jour pour Swift 4.2

Lorsque vous instanciez un UIImage (avec UIImage (nommé: "SomeName"), l'application recherche l'actif dans votre main bundle , ce qui fonctionne normalement. Mais lorsque vous êtes à design time , InterfaceBuilder contient le code des vues pouvant être désignées (pour compilation tant que conception ) dans un paquet séparé.

La solution est donc: Définissez votre bundle de manière dynamique , ainsi vos fichiers peuvent être trouvés dans la conception, la compilation et l'exécution:

    // DYNAMIC BUNDLE DEFINITION FOR DESIGNABLE CLASS
    let dynamicBundle = Bundle(for: type(of: self))

    // OR ALTERNATIVELY BY PROVDING THE CONCRETE NAME OF YOUR DESIGNABLE VIEW CLASS
    let dynamicBundle = Bundle(for: YourDesignableView.self)

    // AND THEN SUCCESSFULLY YOU CAN LOAD THE RESSOURCE
    let image = UIImage(named: "Logo", in: dynamicBundle, compatibleWith: nil)
14
LukeSideWalker

Essayez d’obtenir le paquet de la classe comme ceci:

let bundle = NSBundle(forClass: self.dynamicType)

ou en spécifiant le nom de la classe comme ceci

let bundle = NSBundle(forClass: TestImageView.self)

En supposant que votre image se trouve dans le lot, par exemple Images.xcassets, vous pouvez ensuite la charger en utilisant:

self.image = UIImage("Test", inBundle: bundle, compatibleWithTraitCollection: self.traitCollection)

N'oubliez pas de vérifier si votre image est nulle avant d'essayer de l'utiliser. Je n'ai pas pu obtenir le chemin de l'image à l'aide de bundle.pathForResource pour fonctionner correctement avec les ressources d'image normales. Il ne semble pas non plus exister d'appel UIImage où vous spécifiez uniquement le nom et le bundle, vous devez donc utiliser la collection de traits.

Cette question est liée à:

xcode 6 IB_DESIGNABLE- ne charge pas les ressources de l'ensemble dans le générateur Interface

Réponse de Apple ...

L’ingénierie a déterminé que ce problème se comportait comme prévu sur la base Des éléments suivants:

Nous ne pouvons pas vraiment rendre cela plus facile que de spécifier le paquet. Vous Pourriez dire: "Oh, parlons-en - [NSBundle mainBundle]", mais beaucoup de sites d’appels faisant référence à un paquet ne passent pas par là (ou ne passent pas l’API des FC). On pourrait dire alors "ok, bien alors que diriez-vous de Moins swizzle - [UIImage imageNamed:]". Le problème ici est qu’il n’ya pas de remplacement unique pour le paquet principal. Vous pouvez avoir plusieurs Ensembles de vues en direct (soit des frameworks, soit des applications) chargés en même temps. Par conséquent, nous Ne pouvons pas en choisir un qui sera l'ensemble principal.

Les développeurs doivent connaître les bundles et savoir comment obtenir des images d'un Bundle. Les développeurs doivent utiliser UIImage (nommé: inBundle: compatibleWithTraitCollection :) pour toutes les recherches d’image.

51
kasplat

Permet de faire apparaître la réponse Swift 3

let bundle = Bundle(for: self.classForCoder)
... UIImage(named: "AnImageInYourAssetsFolderPerhaps", in: bundle, compatibleWith: self.traitCollection)!
7
RyanTCB

Pour Swift 4 (et 3), utilisez ceci:

let image = UIImage(named: "foo", in: Bundle(for: type(of: self)), compatibleWith: traitCollection)

Cette approche obtient le paquet universellement

5
Jakub Truhlář

J'ai pu résoudre le problème d'obtention du chemin d'accès au projet Interface Builder à partir de l'objet NSProcessInfo actuel. Vous pouvez ensuite collecter le chemin correct à partir de la clé IB_PROJECT_SOURCE_DIRECTORIES.

override func prepareForInterfaceBuilder() {
    let processInfo = NSProcessInfo.processInfo()
    let environment = processInfo.environment
    let projectSourceDirectories : AnyObject = environment["IB_PROJECT_SOURCE_DIRECTORIES"]!
    let directories = projectSourceDirectories.componentsSeparatedByString(":")

    if directories.count != 0 {
        let firstPath = directories[0] as String
        let imagePath = firstPath.stringByAppendingPathComponent("PrepareForIBTest/Test.jpg")

        let image = UIImage(contentsOfFile: imagePath)
        self.image = image
    }
}

Cette technique est décrite dans la session "Quoi de neuf dans Interface Builder" dans la session 411 de la WWDC 2014, comme suggéré par bjhomer dans ce message des forums de développement Apple .

De plus, je dois dire que il était nécessaire de passer à une sous-classe UIView, car il semble que l'apparence de la UIImageView ne change pas dans les vues en direct.

5
mxb

Pour Swift 2 et Xcode 7, l'interface a été modifiée. Devrait utiliser 

let bundle = NSBundle(forClass: self.dynamicType)
let image = UIImage(named: "imageName", inBundle: bundle, compatibleWithTraitCollection: self.traitCollection)
let imageView = UIImageView(image: image)

Je l'utilise dans mon projet , cela fonctionne bien pour l'IB et l'appareil.

0
Jake Lin

Cela chargera votre IB_Designable ou, si vous n’en avez pas, l’image par défaut.

- (void)prepareForInterfaceBuilder
{
    NSBundle *bundle = [NSBundle bundleForClass:[self class]];
    imagePic = imagePic ? [imagePic imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] : [UIImage imageNamed:@"goodIcon" inBundle:bundle compatibleWithTraitCollection:self.traitCollection];

}
0