Xcode 5 y Catálogo de activos: ¿Cómo hacer reference a LaunchImage?

Estoy usando el catálogo de activos de Xcode 5, y me gustaría usar mi LaunchImage como image de background de mi vista de inicio (una práctica bastante común para hacer que la transición de "cargar" a "cargado" se vea bien).

Me gustaría usar la misma input en Asset Catalog para ahorrar espacio y no tener que replicar la image en dos Conjuntos de imágenes diferentes.

Sin embargo, llamando:

 UIImage *image = [UIImage imageNamed:@"LaunchImage"]; //returns nil 

Esta es la list (casi) completa de LaunchImage (excluyendo las imágenes de iPad sin barra de estado):

 - (NSString *)splashImageNameForOrientation:(UIInterfaceOrientation)orientation { CGSize viewSize = self.view.bounds.size; NSString* viewOrientation = @"Portrait"; if (UIDeviceOrientationIsLandscape(orientation)) { viewSize = CGSizeMake(viewSize.height, viewSize.width); viewOrientation = @"Landscape"; } NSArray* imagesDict = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"UILaunchImages"]; for (NSDictionary* dict in imagesDict) { CGSize imageSize = CGSizeFromString(dict[@"UILaunchImageSize"]); if (CGSizeEqualToSize(imageSize, viewSize) && [viewOrientation isEqualToString:dict[@"UILaunchImageOrientation"]]) return dict[@"UILaunchImageName"]; } return nil; } 

LaunchImages son especiales, y en realidad no son un catálogo de activos en el dispositivo. Si miras usando iFunBox / iExplorer / etc (o en el simulador o en el directory de compilation), puedes ver los nombres finales y luego escribir código para usarlos, por ejemplo. para un proyecto solo para iOS7 solo para iPhone, esto establecerá la image de inicio correcta:

 NSString *launchImage; if ((UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) && ([UIScreen mainScreen].bounds.size.height > 480.0f)) { launchImage = @"LaunchImage-700-568h"; } else { launchImage = @"LaunchImage-700"; } [self.launchImageView setImage:[UIImage imageNamed:launchImage]]; 

Puse esto en viewDidLoad.

Esto no es realmente ideal, sería genial si Apple nos diera una buena API para hacer esto.

Actualmente, mi aplicación solo admite iOS 7 y versiones posteriores.

Así es como hago reference a la image de lanzamiento del catálogo de activos:

 NSDictionary *dict = @{@"320x480" : @"LaunchImage-700", @"320x568" : @"LaunchImage-700-568h", @"375x667" : @"LaunchImage-800-667h", @"414x736" : @"LaunchImage-800-Portrait-736h"}; NSString *key = [NSString stringWithFormat:@"%dx%d", (int)[UIScreen mainScreen].bounds.size.width, (int)[UIScreen mainScreen].bounds.size.height]; UIImage *launchImage = [UIImage imageNamed:dict[key]]; 

Puede agregar más pares de valores key si desea admitir versiones anteriores de iOS.

Aquí una categoría en UIImage basada en la solución proporcionada por Cherpak Evgeny arriba.

UIImage + SplashImage.h :

 #import <UIKit/UIKit.h> /** * Category on `UIImage` to access the splash image. **/ @interface UIImage (SplashImage) /** * Return the name of the splash image for a given orientation. * @param orientation The interface orientation. * @return The name of the splash image. **/ + (NSString *)si_splashImageNameForOrientation:(UIInterfaceOrientation)orientation; /** * Returns the splash image for a given orientation. * @param orientation The interface orientation. * @return The splash image. **/ + (UIImage*)si_splashImageForOrientation:(UIInterfaceOrientation)orientation; @end 

UIImage + SplashImage.m :

 #import "UIImage+SplashImage.h" @implementation UIImage (SplashImage) + (NSString *)si_splashImageNameForOrientation:(UIInterfaceOrientation)orientation { CGSize viewSize = [UIScreen mainScreen].bounds.size; NSString *viewOrientation = @"Portrait"; if (UIDeviceOrientationIsLandscape(orientation)) { viewSize = CGSizeMake(viewSize.height, viewSize.width); viewOrientation = @"Landscape"; } NSArray* imagesDict = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"UILaunchImages"]; for (NSDictionary *dict in imagesDict) { CGSize imageSize = CGSizeFromString(dict[@"UILaunchImageSize"]); if (CGSizeEqualToSize(imageSize, viewSize) && [viewOrientation isEqualToString:dict[@"UILaunchImageOrientation"]]) return dict[@"UILaunchImageName"]; } return nil; } + (UIImage*)si_splashImageForOrientation:(UIInterfaceOrientation)orientation { NSString *imageName = [self si_splashImageNameForOrientation:orientation]; UIImage *image = [UIImage imageNamed:imageName]; return image; } @end 

@ respuesta de codeman actualizada para Swift 1.2:

 func splashImageForOrientation(orientation: UIInterfaceOrientation, size: CGSize) -> String? { var viewSize = size var viewOrientation = "Portrait" if UIInterfaceOrientationIsLandscape(orientation) { viewSize = CGSizeMake(size.height, size.width) viewOrientation = "Landscape" } if let imagesDict = NSBundle.mainBundle().infoDictionary as? [String: AnyObject] { if let imagesArray = imagesDict["UILaunchImages"] as? [[String: String]] { for dict in imagesArray { if let sizeString = dict["UILaunchImageSize"], let imageOrientation = dict["UILaunchImageOrientation"] { let imageSize = CGSizeFromString(sizeString) if CGSizeEqualToSize(imageSize, viewSize) && viewOrientation == imageOrientation { if let imageName = dict["UILaunchImageName"] { return imageName } } } } } } return nil } 

Para llamarlo y para admitir la rotation para iOS 8:

 override func viewWillAppear(animated: Bool) { if let img = splashImageForOrientation(UIApplication.shanetworkingApplication().statusBarOrientation, size: self.view.bounds.size) { backgroundImage.image = UIImage(named: img) } } override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { let orientation = size.height > size.width ? UIInterfaceOrientation.Portrait : UIInterfaceOrientation.LandscapeLeft if let img = splashImageForOrientation(orientation, size: size) { backgroundImage.image = UIImage(named: img) } } 

Justo lo que necesitaba, gracias!

Acabo de escribir un método general para get el nombre de la image splash para iPhone y iPad (Landscape, Portrait). Funcionó para mí, Hope It te ayuda también. Escribí esto con ayuda de otras respuestas de SO, gracias @Pichirichi para la list completa.

 +(NSString*)getLaunchImageName { NSArray* images= @[@"LaunchImage.png", @"LaunchImage@2x.png",@"LaunchImage-700@2x.png",@"LaunchImage-568h@2x.png",@"LaunchImage-700-568h@2x.png",@"LaunchImage-700-Portrait@2x~ipad.png",@"LaunchImage-Portrait@2x~ipad.png",@"LaunchImage-700-Portrait~ipad.png",@"LaunchImage-Portrait~ipad.png",@"LaunchImage-Landscape@2x~ipad.png",@"LaunchImage-700-Landscape@2x~ipad.png",@"LaunchImage-Landscape~ipad.png",@"LaunchImage-700-Landscape~ipad.png"]; UIImage *splashImage; if ([self isDeviceiPhone]) { if ([self isDeviceiPhone4] && [self isDeviceRetina]) { splashImage = [UIImage imageNamed:images[1]]; if (splashImage.size.width!=0) return images[1]; else return images[2]; } else if ([self isDeviceiPhone5]) { splashImage = [UIImage imageNamed:images[1]]; if (splashImage.size.width!=0) return images[3]; else return images[4]; } else return images[0]; //Non-retina iPhone } else if ([[UIDevice currentDevice] orientation]==UIDeviceOrientationPortrait || [[UIDevice currentDevice] orientation] == UIDeviceOrientationPortraitUpsideDown)//iPad Portrait { if ([self isDeviceRetina]) { splashImage = [UIImage imageNamed:images[5]]; if (splashImage.size.width!=0) return images[5]; else return images[6]; } else { splashImage = [UIImage imageNamed:images[7]]; if (splashImage.size.width!=0) return images[7]; else return images[8]; } } else { if ([self isDeviceRetina]) { splashImage = [UIImage imageNamed:images[9]]; if (splashImage.size.width!=0) return images[9]; else return images[10]; } else { splashImage = [UIImage imageNamed:images[11]]; if (splashImage.size.width!=0) return images[11]; else return images[12]; } } } 

Otros methods de utilidad son:

 +(BOOL)isDeviceiPhone { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { return TRUE; } return FALSE; } +(BOOL)isDeviceiPhone4 { if ([[UIScreen mainScreen] bounds].size.height==480) return TRUE; return FALSE; } +(BOOL)isDeviceRetina { if ([[UIScreen mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)] && ([UIScreen mainScreen].scale == 2.0)) // Retina display { return TRUE; } else // non-Retina display { return FALSE; } } +(BOOL)isDeviceiPhone5 { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone && [[UIScreen mainScreen] bounds].size.height>480) { return TRUE; } return FALSE; } 

Versión rápida de la respuesta de Cherpak Evgeny:

  func splashImageForOrientation(orientation: UIInterfaceOrientation) -> String { var viewSize = self.view.bounds.size var viewOrientation = "Portrait" if UIInterfaceOrientationIsLandscape(orientation) { viewSize = CGSizeMake(viewSize.height, viewSize.width) viewOrientation = "Landscape" } let imagesDict = NSBundle.mainBundle().infoDictionary as Dictionary<NSObject,AnyObject>! let imagesArray = imagesDict["UILaunchImages"] as NSArray for dict in imagesArray { let dictNSDict = dict as NSDictionary let imageSize = CGSizeFromString(dictNSDict["UILaunchImageSize"] as String) if CGSizeEqualToSize(imageSize, viewSize) && viewOrientation == (dictNSDict["UILaunchImageOrientation"] as String) { return dictNSDict["UILaunchImageName"] as String } } return "" } 

Siguiendo la respuesta de @Pichirich, hice reference a mi image de lanzamiento en InterfaceBuilder como:

"LaunchImage.png"

… y con Xcode 5.0.2, arranca automáticamente la image apropiada directamente del Asset Catalog.

Esto es lo que espero, excepto por el movimiento brutalmente desagradable de Apple de cambiar en silencio el nombre "Default.png" a "LaunchImage.png" 🙂

En la documentation se indica claramente:

"Cada set en un catálogo de activos tiene un nombre . Puede usar ese nombre para cargar mediante progtwigción cualquier image individual contenida en el set. Para cargar una image, llame al método UIImage: ImageNamed: pasa el nombre del set que contiene la image "

Usar la list de Pichirichi ayuda a resolver esta inconsistencia.

Uno puede acceder fácilmente a la image de lanzamiento por una línea de código.

  UIImage *myAppsLaunchImage = [UIImage launchImage]; 

Siga los pasos que se detallan a continuación para lograr la funcionalidad que se muestra arriba.

Paso 1. Extienda la class UIImage creando una categoría y agregue el siguiente método.

 + (UIImage *)launchImage { NSDictionary *dOfLaunchImage = [NSDictionary dictionaryWithObjectsAndKeys: @"LaunchImage-568h@2x.png",@"568,320,2,8,p", // ios 8 - iphone 5 - portrait @"LaunchImage-568h@2x.png",@"568,320,2,8,l", // ios 8 - iphone 5 - landscape @"LaunchImage-700-568h@2x.png",@"568,320,2,7,p", // ios 7 - iphone 5 - portrait @"LaunchImage-700-568h@2x.png",@"568,320,2,7,l", // ios 7 - iphone 5 - landscape @"LaunchImage-700-Landscape@2x~ipad.png",@"1024,768,2,7,l", // ios 7 - ipad retina - landscape @"LaunchImage-700-Landscape~ipad.png",@"1024,768,1,7,l", // ios 7 - ipad regular - landscape @"LaunchImage-700-Portrait@2x~ipad.png",@"1024,768,2,7,p", // ios 7 - ipad retina - portrait @"LaunchImage-700-Portrait~ipad.png",@"1024,768,1,7,p", // ios 7 - ipad regular - portrait @"LaunchImage-700@2x.png",@"480,320,2,7,p", // ios 7 - iphone 4/4s retina - portrait @"LaunchImage-700@2x.png",@"480,320,2,7,l", // ios 7 - iphone 4/4s retina - landscape @"LaunchImage-Landscape@2x~ipad.png",@"1024,768,2,8,l", // ios 8 - ipad retina - landscape @"LaunchImage-Landscape~ipad.png",@"1024,768,1,8,l", // ios 8 - ipad regular - landscape @"LaunchImage-Portrait@2x~ipad.png",@"1024,768,2,8,p", // ios 8 - ipad retina - portrait @"LaunchImage-Portrait~ipad.png",@"1024,768,1,8,l", // ios 8 - ipad regular - portrait @"LaunchImage.png",@"480,320,1,7,p", // ios 6 - iphone 3g/3gs - portrait @"LaunchImage.png",@"480,320,1,7,l", // ios 6 - iphone 3g/3gs - landscape @"LaunchImage@2x.png",@"480,320,2,8,p", // ios 6,7,8 - iphone 4/4s - portrait @"LaunchImage@2x.png",@"480,320,2,8,l", // ios 6,7,8 - iphone 4/4s - landscape @"LaunchImage-800-667h@2x.png",@"667,375,2,8,p", // ios 8 - iphone 6 - portrait @"LaunchImage-800-667h@2x.png",@"667,375,2,8,l", // ios 8 - iphone 6 - landscape @"LaunchImage-800-Portrait-736h@3x.png",@"736,414,3,8,p", // ios 8 - iphone 6 plus - portrait @"LaunchImage-800-Landscape-736h@3x.png",@"736,414,3,8,l", // ios 8 - iphone 6 plus - landscape nil]; NSInteger width = ([UIScreen mainScreen].bounds.size.width>[UIScreen mainScreen].bounds.size.height)?[UIScreen mainScreen].bounds.size.width:[UIScreen mainScreen].bounds.size.height; NSInteger height = ([UIScreen mainScreen].bounds.size.width>[UIScreen mainScreen].bounds.size.height)?[UIScreen mainScreen].bounds.size.height:[UIScreen mainScreen].bounds.size.width; NSInteger os = [[[[[UIDevice currentDevice] systemVersion] componentsSeparatedByString:@"."] objectAtIndex:0] integerValue]; NSString *strOrientation = UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation])?@"l":@"p"; NSString *strImageName = [NSString stringWithFormat:@"%li,%li,%li,%li,%@",width,height,(NSInteger)[UIScreen mainScreen].scale,os,strOrientation]; UIImage *imageToReturn = [UIImage imageNamed:[dOfLaunchImage valueForKey:strImageName]]; if([strOrientation isEqualToString:@"l"] && [strImageName rangeOfString:@"Landscape"].length==0) { imageToReturn = [UIImage rotate:imageToReturn orientation:UIImageOrientationRight]; } return imageToReturn; } 

Paso 2. El método anterior debería funcionar agregando el siguiente código también en la misma categoría de UIImage

 static inline double radians (double degrees) {return degrees * M_PI/180;} + (UIImage *)rotate:(UIImage*)src orientation:(UIImageOrientation) orientation { UIGraphicsBeginImageContext(src.size); CGContextRef context = UIGraphicsGetCurrentContext(); if (orientation == UIImageOrientationRight) { CGContextRotateCTM (context, radians(90)); } else if (orientation == UIImageOrientationLeft) { CGContextRotateCTM (context, radians(-90)); } else if (orientation == UIImageOrientationDown) { // NOTHING } else if (orientation == UIImageOrientationUp) { CGContextRotateCTM (context, radians(90)); } [src drawAtPoint:CGPointMake(0, 0)]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; } 

Me doy count de que esta no es necesariamente la mejor solución para todos, pero la forma más fácil (y less propensa a errores, en mi humilde opinión) es hacer una input separada en su catálogo Images.xcassets. Lo llamé SplashImage .

Cuando vaya a agregar una nueva input, asegúrese de no seleccionar "Nueva image de lanzamiento" como opción. En su lugar, select el genérico "Nuevo set de imágenes". A continuación, abra el inspector y select las opciones relevantes. Si estás construyendo solo para dispositivos Retina, como lo era yo, puedes seleccionar lo siguiente:

inspector de imagen

Esto te dejará con cuatro inputs (iPhone 4S, iPhone 5 (s, c), iPhone 6 y iPhone 6 Plus).

imágenes

Los files correspondientes a las imágenes son los siguientes:

 | Resolution (Xcode entry) | Launch Image name | Device | |--------------------------|---------------------|------------------| | 1x | Default-750.png | iPhone 6 | | 2x | Default@2x.png | iPhone 4S | | Retina 4 2x | Default-568h@2x.png | iPhone 5, 5s, 5c | | 3x | Default-1242.png | iPhone 6 Plus | 

Por supuesto, después de que hayas hecho esto, simplemente puedes usar [UIImage imageNamed:@"SplashImage"]

Con la ayuda de la respuesta de Pichirichi, he implementado la siguiente categoría (iOS 7+): UIImage + AssetLaunchImage

En realidad, es poco más que generar un nombre sobre la marcha, pero probablemente sea útil.