Xcode 5和资源目录:如何引用启动图片?

102

我正在使用Xcode 5的资源目录,我希望将我的 LaunchImage 用作主视图的背景图像(这是使从“加载”到“已加载”转换看起来平滑的常见做法)。

我想使用资源目录中相同的条目来节省空间,而不必在两个不同的图像集中复制图像。

但是,调用:

UIImage *image = [UIImage imageNamed:@"LaunchImage"]; //returns nil
14个回答

83

这是LaunchImage(不包括没有状态栏的iPad图像)的(几乎)完整列表:

  • LaunchImage-568h@2x.png
  • LaunchImage-700-568h@2x.png
  • LaunchImage-700-Landscape@2x~ipad.png
  • LaunchImage-700-Landscape~ipad.png
  • LaunchImage-700-Portrait@2x~ipad.png
  • LaunchImage-700-Portrait~ipad.png
  • LaunchImage-700@2x.png
  • LaunchImage-Landscape@2x~ipad.png
  • LaunchImage-Landscape~ipad.png
  • LaunchImage-Portrait@2x~ipad.png
  • LaunchImage-Portrait~ipad.png
  • LaunchImage.png
  • LaunchImage@2x.png
  • LaunchImage-800-667h@2x.png(iPhone 6)
  • LaunchImage-800-Portrait-736h@3x.png(iPhone 6 Plus竖屏)
  • LaunchImage-800-Landscape-736h@3x.png(iPhone 6 Plus横屏)
  • LaunchImage-1100-Portrait-2436h@3x.png(iPhone X竖屏)
  • LaunchImage-1100-Landscape-2436h@3x.png(iPhone X横屏)

有人知道没有状态栏的iPad图片吗? - Mohamed Hafez
1
@Mohamed Hafez:Pichirichi 实际上已经将它们包含在他的清单中。它们分别是 LaunchImage-Portraitipad.png、LaunchImage-Portrait@2xipad.png、LaunchImage-Landscapeipad.png 和 LaunchImage-Landscape@2xipad.png。 - John Jacecko
数字700和800代表什么意思? - Sound Blaster
2
我明白了,它指的是iOS 7和8。 - Sound Blaster
4
XCode 会自动为这些图像资源创建文件名,让你费尽周折才能直接访问它们,这真的很烦人。 - Mr. T
显示剩余3条评论

67
- (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;
}

1
非常好。搜索主捆绑包的信息字典以查找可用的启动图像,然后选择分辨率匹配的图像是一个聪明而优雅的方法! - iOSX
1
这是一个非常棒的想法,比我的好得多,而且也具有未来的可扩展性,除非苹果改变 info.plist 的结构。 - nonamelive
1
这是一个非常聪明的解决方案。在我的Xcode项目中,我有多个目标,只使用LaunchImage字符串并不总是返回正确的图像。非常感谢。 - Enrico Susatyo
3
虽然是个绝妙的想法,但对于有不透明状态栏的屏幕无法使用。因此需要将self.view.bounds.size更改为[UIScreen mainScreen].bounds.size。 - RamaKrishna Chunduri
1
很好的解决方案。需要进行小修改:UIInterfaceOrientation和UIDeviceOrientation之间存在隐式转换。请改用UIInterfaceOrientationIsLandscape() - Almog C
显示剩余8条评论

52

LaunchImages是特殊的,实际上并不是设备上的资产目录。如果您使用iFunBox/iExplorer等工具(或者在模拟器、构建目录中查看),则可以看到最终名称,并编写代码来使用它们-例如,对于仅针对iOS7的iPhone项目,这将设置正确的启动图像:

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]];

我把这放到viewDidLoad里了。

这并不是最理想的做法,如果苹果能给我们一个好的API来做这个就太好了。


2
这对我起作用了,但我真的希望有一种更简单的方法来引用启动图像。 - Zorayr
可能在Xcode 5.0.2中已经修复 - 请参见下文,对我来说似乎只需引用“LaunchImage.png”即可正常工作。 - Adam
1
@Adam 如果那是真的就太好了!我刚在iphone5s/xcode5.0.2/ios7.0.4上尝试了一下,[UIImage imageNamed:@"LaunchImage.png"]返回了nil。 - JosephH
@JosephH 嗯。也许需要创建一个新项目?这个项目是在 Xcode 5.0.2 中创建的,唯一更改的是“禁用 ARC”。它运行得很好 : )。我会看看能否找到其他东西,但不知道我可能还改了什么。 - Adam
我尝试了类似的代码,但是使用了“Default”和“Default-568h”(原始资源文件名称)。在查看导出的应用程序包内部后,我意识到Xcode将名称更改为“LaunchImage-700*”。 - Nicolas Miari

27

我的应用目前仅支持 iOS 7 及更高版本。

这是我从资源目录引用启动图像的方式:

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]];

如果您希望支持较旧版本的iOS,可以添加更多的键值对。


1
请注意,从iOS 8开始,UIScreen.mainScreen.bounds根据当前界面方向而有所不同。请参阅https://dev59.com/amAf5IYBdhLWcg3w52Pm#24153540。 - Jean Regisser
1
谢谢,这正是我在寻找的! - Joseph Paterson
谢谢这个,有什么方法可以访问应用程序图标吗? - AsifHabib

10

这里是基于Cherpak Evgeny所提供的解决方案而创建的UIImage类别。

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

imageNamed方法将图片推送到系统缓存中,但启动图有时非常巨大,因此它会一直存在于内存中,直到缓存刷新。 - Igor Palaguta

9

@codeman的答案已更新,适用于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

}

为了支持 iOS 8 的旋转,需要调用它:

override func viewWillAppear(animated: Bool) {
    if let img = splashImageForOrientation(UIApplication.sharedApplication().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)
    }

}
< p >我正需要这个,谢谢!< /p >

7

我刚写了一个通用方法来获取iPhone和iPad(横屏、竖屏)的启动图像的名称,对于我来说它是有效的,希望它也能帮到你。我在其他SO答案的帮助下编写了这个方法,感谢@Pichirichi提供的整个列表。

+(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];
    }
 }
}

其他实用方法包括

+(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;
}

这段代码中isDeviceiPhone4:实际上有一个小bug:[[UIScreen mainScreen] bounds]在iOS 8下会根据设备方向发生变化。您需要显式地将其转换为竖屏bounds,例如[screen.coordinateSpace convertRect:screen.bounds toCoordinateSpace:screen.fixedCoordinateSpace],但一定要先测试是否在iOS 8上运行,否则可能会导致崩溃。 - Mohamed Hafez
感谢@Hafez指出这一点,我将在iOS 8上进行测试并尽快更新答案。 - zaheer

7

以下是Cherpak Evgeny的回答的Swift版本:

    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 ""
    }

5

根据@Pichirich的答案,我在InterfaceBuilder中引用我的启动图像:

"LaunchImage.png"

... 使用Xcode 5.0.2,它会自动从资源目录中直接获取适当的图像。

这是我所期望的 - 除了苹果恶意地将 "Default.png" 静默重命名为 "LaunchImage.png" :)


还有一件事需要注意。这些图片的尺寸应该完全按照苹果的建议(例如,对于iOS 5-6 iPhone 3GS的LaunchImage,尺寸应为320x480),否则在给定的初始化后将会是nil - Alexander Kostiev

3

通过一行代码,您可以轻松访问启动画面。

 UIImage *myAppsLaunchImage = [UIImage launchImage];

请按照以下步骤实现上述功能: 步骤1。 通过创建一个分类来扩展UIImage类,然后添加以下方法。
+ (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;
}

步骤 2. 在同一类别的 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;
}

非常好的回答,谢谢! - dortzur
1
现在iPhone X发布的启动图像叫什么名字? - RPM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接