iOS 7 / Xcode 5:以编程方式访问设备启动图像

时间:2013-10-16 17:35:41

标签: ios objective-c xcode ios7

有没有办法将应用程序LaunchImage用作通用iOS应用程序中的背景,而无需在多个位置放置相同的图像资源?

我无法访问LaunchImage中的Images.xcassets文件,因此我创建了两个新的图像集“背景肖像”和“背景风景”(因为似乎无法放置)将风景和肖像图像放入同一组中。)

虽然这个解决方法完成了这些工作,但我不愿意将每个图像都包含在应用程序中两次。这也具有很高的维护成本。

有关如何访问当前设备的LaunchImage的任何建议都表示赞赏。

GCOLaunchImageTransition必须完成iOS的工作< 7。

15 个答案:

答案 0 :(得分:56)

您可以复制/粘贴以下代码,以便在运行时加载应用的启动图像:

// Load launch image
NSString *launchImageName;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
    if ([UIScreen mainScreen].bounds.size.height == 480) launchImageName = @"LaunchImage-700@2x.png"; // iPhone 4/4s, 3.5 inch screen
    if ([UIScreen mainScreen].bounds.size.height == 568) launchImageName = @"LaunchImage-700-568h@2x.png"; // iPhone 5/5s, 4.0 inch screen
    if ([UIScreen mainScreen].bounds.size.height == 667) launchImageName = @"LaunchImage-800-667h@2x.png"; // iPhone 6, 4.7 inch screen
    if ([UIScreen mainScreen].bounds.size.height == 736) launchImageName = @"LaunchImage-800-Portrait-736h@3x.png"; // iPhone 6+, 5.5 inch screen
}
else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
    if ([UIScreen mainScreen].scale == 1) launchImageName = @"LaunchImage-700-Portrait~ipad.png"; // iPad 2
    if ([UIScreen mainScreen].scale == 2) launchImageName = @"LaunchImage-700-Portrait@2x~ipad.png"; // Retina iPads
}
self.launchImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:launchImageName]];

答案 1 :(得分:42)

您可以使用启动图像,而无需包含它们两次。关键是当您使用资产目录时,应用程序包中包含的图像的文件名是(有点)标准化的,可能与您为原始文件命名的内容无关。

特别是,当您使用LaunchImage图像集时,最终在应用程序包中的文件具有类似

的名称
  • LaunchImage.png
  • LaunchImage@2x.png
  • LaunchImage-700@2x.png
  • LaunchImage-568h@2x.png
  • LaunchImage-700-568h@2x.png
  • LaunchImage-700-Landscape@2x~ipad.png

等。请注意,特别是它们未命名为Default.png或其任何变体。即使那就是你所谓的文件。一旦你将它们放入资产目录中的一个中,它们就会以标准名称出现在另一端。

因此,[UIImage imageNamed:@"Default"]无效,因为应用包中没有此类文件。但是,[UIImage imageNamed:@"LaunchImage"]将起作用(假设您已经填充了iPhone Portrait 2x或者 pre iOS7 iPhone Portrait 1x)。

文档指出imageNamed:上的UIImage方法应该自动选择正确的版本,但我认为这仅适用于启动图像以外的图像集 - 至少我是没有让它正常工作(可能只是我没有做正确的事情)。

因此,根据您的具体情况,您可能需要进行一些试验和错误才能获得正确的文件名。在模拟器中构建并运行应用程序,然后您可以始终查看~/Library/Application Support/iPhone Simulator的相应子目录,以验证应用程序包中的实际文件名是什么。

但同样重要的是,重点是不需要包含图像文件的副本,也不需要对Copy Bundle Resources构建阶段进行任何调整。

答案 2 :(得分:41)

大多数答案都需要根据设备类型,比例,大小等创建图像名称。但正如Matthew Burke指出的那样,启动图像目录中的每个图像都将重命名为" LaunchImage *"因此我们能够遍历我们的发布图像并找到(对于当前设备)适当的图像。在Objective-C中,它看起来像这样:

NSArray *allPngImageNames = [[NSBundle mainBundle] pathsForResourcesOfType:@"png"
                                        inDirectory:nil];

for (NSString *imgName in allPngImageNames){
    // Find launch images
    if ([imgName containsString:@"LaunchImage"]){
        UIImage *img = [UIImage imageNamed:imgName];
        // Has image same scale and dimensions as our current device's screen?
        if (img.scale == [UIScreen mainScreen].scale && CGSizeEqualToSize(img.size, [UIScreen mainScreen].bounds.size)) {
            NSLog(@"Found launch image for current device %@", img.description);
            break;
        }
    }
}

(请注意,此代码使用iOS 8中引入的" containsString"方法。对于以前的iOS版本,使用" rangeOfString")

答案 3 :(得分:10)

以下是我在iOS 7.0+中测试时的结果,只有纵向:

3.5 inch screen: LaunchImage-700@2x.png
4.0 inch screen: LaunchImage-700-568h@2x.png
4.7 inch screen: LaunchImage-800-667h@2x.png
5.5 inch screen: LaunchImage-800-Portrait-736h@3x.png
iPad2          : LaunchImage-700-Portrait~ipad.png
Retina iPads   : LaunchImage-700-Portrait@2x~ipad.png

答案 4 :(得分:9)

Daniel Witurna的优秀answer的Swift版本,不需要检查所有已知设备类型或方向的列表。

func appLaunchImage() -> UIImage?
{
    let allPngImageNames = NSBundle.mainBundle().pathsForResourcesOfType("png", inDirectory: nil)

    for imageName in allPngImageNames
    {
        guard imageName.containsString("LaunchImage") else { continue }

        guard let image = UIImage(named: imageName) else { continue }

        // if the image has the same scale AND dimensions as the current device's screen...

        if (image.scale == UIScreen.mainScreen().scale) && (CGSizeEqualToSize(image.size, UIScreen.mainScreen().bounds.size))
        {
            return image
        }
    }

    return nil
}

答案 5 :(得分:4)

捆绑包中的

Info.plist包含启动图像信息,包括启动图像的名称。

目标-C:

- (UIImage *)getCurrentLaunchImage {
    CGSize screenSize = [UIScreen mainScreen].bounds.size;

    NSString *interfaceOrientation = nil;
    if (([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortraitUpsideDown) ||
        ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortrait)) {
        interfaceOrientation = @"Portrait";
    } else {
        interfaceOrientation = @"Landscape";
    }

    NSString *launchImageName = nil;

    NSArray *launchImages = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"UILaunchImages"];
    for (NSDictionary *launchImage in launchImages) {
        CGSize launchImageSize = CGSizeFromString(launchImage[@"UILaunchImageSize"]);
        NSString *launchImageOrientation = launchImage[@"UILaunchImageOrientation"];

        if (CGSizeEqualToSize(launchImageSize, screenSize) &&
            [launchImageOrientation isEqualToString:interfaceOrientation]) {
            launchImageName = launchImage[@"UILaunchImageName"];
            break;
        }
    }

    return [UIImage imageNamed:launchImageName];
}
斯威夫特4:

func getCurrentLaunchImage() -> UIImage? {

    guard let launchImages = Bundle.main.infoDictionary?["UILaunchImages"] as? [[String: Any]] else { return nil }

    let screenSize = UIScreen.main.bounds.size

    var interfaceOrientation: String
    switch UIApplication.shared.statusBarOrientation {
    case .portrait,
         .portraitUpsideDown:
        interfaceOrientation = "Portrait"
    default:
        interfaceOrientation = "Landscape"
    }

    for launchImage in launchImages {

        guard let imageSize = launchImage["UILaunchImageSize"] as? String else { continue }
        let launchImageSize = CGSizeFromString(imageSize)

        guard let launchImageOrientation = launchImage["UILaunchImageOrientation"] as? String else { continue }

        if
            launchImageSize.equalTo(screenSize),
            launchImageOrientation == interfaceOrientation,
            let launchImageName = launchImage["UILaunchImageName"] as? String {
            return UIImage(named: launchImageName)
        }
    }

    return nil
}

答案 6 :(得分:1)

我不知道这是否是您通过代码访问的意思。但是,如果您选择“project-> target->构建阶段 - >复制捆绑资源”,请单击“+”和“添加其他”导航到您的Images.xcassets-> LaunchImage.launchimage并选择任何png的你想使用并点击“打开”。现在您可以使用[UIImage imageNamed:@"Default"];

之类的图像

答案 7 :(得分:1)

如果您需要确定设备,我会使用以下代码(它有点快速和肮脏,但它可以解决问题)

if( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone ){

    CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height;
    CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
    if( screenHeight < screenWidth ){
        screenHeight = screenWidth;
    }

    if( screenHeight > 480 && screenHeight < 667 ){
        DLog(@"iPhone 5/5s");
    } else if ( screenHeight > 480 && screenHeight < 736 ){
        DLog(@"iPhone 6");
    } else if ( screenHeight > 480 ){
        DLog(@"iPhone 6 Plus");
    } else {
        DLog(@"iPhone 4/4s");
    }
}

答案 8 :(得分:1)

Matthew Burke的回答是正确的答案。下面是我正在使用的代码,用于iOS9 / Xcode7,为iOS7及更高版本构建应用程序,适用于iPhone和iPad,允许使用横向。

首先,详细说明一下: 在iOS8 / Xcode6中,如果您使用故事板启动屏幕文件,在应用启动时,应用程序将以正确的分辨率为您的设备创建该启动屏幕文件的2个图像(一个肖像,一个横向),您就可以获得来自文件路径的图像。 (我相信它存储在Library / LaunchImage文件夹中)。

然而,在iOS9 / XCode 7中,不再创建此图像(尽管快照文件夹中有一个快照,但它有一个不断变化的名称,所以如果你想在其他地方使用你的LaunchImage)您的代码,您必须使用启动图像源(最好通过资产目录,因为App Thinning)。现在,正如Matthew Burke所解释的那样,你无法通过这样做来达到那个形象:

let launchImage = UIImage(named: "LaunchImage")

即使资产目录中的图像名称是LaunchImage,Xcode / iOS9也不会让你。

幸运的是,您不必在资产目录中再次包含启动图像。幸运的是,如果您为所有设备制作应用程序,这意味着您的应用程序下载大小将增加20MB。

那么,如何获得那些发布图像呢?嗯,这是步骤:

  1. 创建启动图像并将其放入资产目录中。图像名称并不重要。
  2. 确保您的启动屏幕文件(在目标的常规设置下)为空,并从您的设备和模拟器中删除您的应用。 (只是删除文件名并重新运行不会这样做,你必须先删除你的应用程序)
  3. 在模拟器中运行您的应用程序,然后转到〜/ Library / Application Support / iPhone Simulator文件夹,在那里找到您的应用程序。 (这有点麻烦,因为文件夹名称是无意义的。)显示.app文件的包内容,在那里你会看到几个以“LaunchImage- ...”开头的图像文件。在我的例子中有9个图像因为我正在为iOS7及以上的iPhone和iPad制作应用程序。
  4. 然后,在您的代码中,您需要确定您的应用运行的设备,以及它是纵向还是横向,然后决定使用哪个图像。为了使这更容易,我使用了这个框架:https://github.com/InderKumarRathore/DeviceGuru。是商品,它还没有包括最新的设备(iPhone 6s和iPhone 6s plus),所以你必须在他的swift文件中添加一行。然后,将下面的代码放在你想要你的launchImage的vc中,然后你去:

    func launchImage() -> UIImage? {
        if let launchImageName = launcheImageName() {
            print(launchImageName)
            return UIImage(named: launchImageName)
        }
        else {
            print("no launch image")
            return nil
        }
    }
    
    func launcheImageName() -> String? {
        let HD35 = "LaunchImage-700@2x.png"
        let HD40 = "LaunchImage-700-568h@2x"
        let HD47 = "LaunchImage-800-667h@2x.png"
        var HD55 = "LaunchImage-800-Portrait-736h@3x.png"
        var padHD = "LaunchImage-700-Portrait@2x~ipad.png"
        var pad = "LaunchImage-700-Portrait~ipad.png"
    
        if UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeLeft || UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeRight {
            HD55 = "LaunchImage-800-Landscape-736h@3x.png"
            padHD = "LaunchImage-700-Landscape@2x~ipad.png"
            pad = "LaunchImage-700-Landscape~ipad.png"
        }
    
        let hardware = hardwareString()
        if (hardware == "iPhone1,1")            { return HD35 }
        if (hardware == "iPhone1,2")            { return HD35 }
        if (hardware == "iPhone2,1")            { return HD35 }
        if (hardware == "iPhone3,1")            { return HD35 }
        if (hardware == "iPhone3,2")            { return HD35 }
        if (hardware == "iPhone3,3")            { return HD35 }
        if (hardware == "iPhone4,1")            { return HD35 }
        if (hardware == "iPhone5,1")            { return HD40 }
        if (hardware == "iPhone5,2")            { return HD40 }
        if (hardware == "iPhone5,3")            { return HD40 }
        if (hardware == "iPhone5,4")            { return HD40 }
        if (hardware == "iPhone6,1")            { return HD40 }
        if (hardware == "iPhone6,2")            { return HD40 }
        if (hardware == "iPhone7,1")            { return HD55 }
        if (hardware == "iPhone7,2")            { return HD47 }
        if (hardware == "iPhone8,1")            { return HD55 }
        if (hardware == "iPhone8,2")            { return HD47 }
    
        if (hardware == "iPod1,1")              { return HD35 }
        if (hardware == "iPod2,1")              { return HD35 }
        if (hardware == "iPod3,1")              { return HD35 }
        if (hardware == "iPod4,1")              { return HD35 }
        if (hardware == "iPod5,1")              { return HD40 }
    
        if (hardware == "iPad1,1")              { return pad }
        if (hardware == "iPad1,2")              { return pad }
        if (hardware == "iPad2,1")              { return pad }
        if (hardware == "iPad2,2")              { return pad }
        if (hardware == "iPad2,3")              { return pad }
        if (hardware == "iPad2,4")              { return pad }
        if (hardware == "iPad2,5")              { return pad }
        if (hardware == "iPad2,6")              { return pad }
        if (hardware == "iPad2,7")              { return pad }
        if (hardware == "iPad3,1")              { return padHD }
        if (hardware == "iPad3,2")              { return padHD }
        if (hardware == "iPad3,3")              { return padHD }
        if (hardware == "iPad3,4")              { return padHD }
        if (hardware == "iPad3,5")              { return padHD }
        if (hardware == "iPad3,6")              { return padHD }
        if (hardware == "iPad4,1")              { return padHD }
        if (hardware == "iPad4,2")              { return padHD }
        if (hardware == "iPad4,3")              { return padHD }
        if (hardware == "iPad4,4")              { return padHD }
        if (hardware == "iPad4,5")              { return padHD }
        if (hardware == "iPad4,6")              { return padHD }
        if (hardware == "iPad4,7")              { return padHD }
        if (hardware == "iPad4,8")              { return padHD }
        if (hardware == "iPad5,3")              { return padHD }
        if (hardware == "iPad5,4")              { return padHD }
    
        if (hardware == "i386")                 { return HD55 }
        if (hardware == "x86_64")               { return HD55 }
        if (hardware.hasPrefix("iPhone"))       { return HD55 }
        if (hardware.hasPrefix("iPod"))         { return HD55 }
        if (hardware.hasPrefix("iPad"))         { return padHD }
    
        //log message that your device is not present in the list
        logMessage(hardware)
    
        return nil
    }
    

答案 9 :(得分:1)

 if (IS_IPHONE_4_OR_LESS) {
    self.imageView.image = [UIImage imageNamed:@"LaunchImage-700@2x.png"];
}
else if (IS_IPHONE_5){
     self.imageView.image = [UIImage imageNamed:@"LaunchImage-700-568h@2x.png"];
}
else if (IS_IPHONE_6){
     self.imageView.image = [UIImage imageNamed:@"LaunchImage-800-667h@2x.png"];
}
else if (IS_IPHONE_6P){
      self.imageView.image = [UIImage imageNamed:@"LaunchImage-800-Portrait-736h@3x.png"];
}

答案 10 :(得分:1)

以下是基于Daniel Witurna解决方案的修改代码。此代码段使用谓词从包图像列表中过滤启动图像名称。谓词可能会避免多个循环来从图像路径数组中过滤启动图像。

-(NSString *)getLaunchImageName{

NSArray *allPngImageNames = [[NSBundle mainBundle] pathsForResourcesOfType:@"png" inDirectory:nil];
NSString *expression=[NSString stringWithFormat:@"SELF contains '%@'",@"LaunchImage"];

NSArray *res = [allPngImageNames filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:expression]];

NSString *launchImageName;
for (launchImageName in res){
    {
        UIImage *img = [UIImage imageNamed:launchImageName];
        // Has image same scale and dimensions as our current device's screen?
        if (img.scale == [UIScreen mainScreen].scale && CGSizeEqualToSize(img.size, [UIScreen mainScreen].bounds.size)) {
            NSLog(@"Found launch image for current device %@", img.description);
            break;
        }

    }

}
return launchImageName; }

答案 11 :(得分:0)

创建Images.xcassets后,只需将LaunchImage重命名为Default

如果您支持iOS5和iOS6,这将节省很多麻烦。

“文件夹”/类别的实际名称将在构建时跟随资产。 马修伯克所说的其他一切都是真的;)

答案 12 :(得分:0)

在项目中创建一个新组,而不是由任何物理目录支持。直接从LaunchImage.launchimage将您的启动图片导入该群组。瞧。

答案 13 :(得分:0)

基于Daniel的excellent answer的另一种更现代,更优雅的解决方案:

extension UIImage {
    static var launchImage: UIImage? {
        let pngs = Bundle.main.paths(forResourcesOfType: "png", inDirectory: nil)
        return pngs
            .filter({$0.contains("LaunchImage")})
            .compactMap({UIImage(named: $0)})
            .filter({$0.size == UIScreen.main.bounds.size})
            .first
    } 
}

那样,您可以编写:

let myLaunchImage = UIImage.launchImage

答案 14 :(得分:-1)

由于“LaunchImage”资产实际上是一个自定义野兽......

我的建议是创建一个二级资产目录,其中包含图像副本(或您实际需要的子集)。

我称之为 FauxLaunchImage 。他们可以像你想要的那样访问它

[UIImage imageNamed:@"FauxLaunchImage"];