简体   繁体   English

Xcode 5和资产目录:如何引用LaunchImage?

[英]Xcode 5 & Asset Catalog: How to reference the LaunchImage?

I am using Xcode 5's Asset Catalog, and I would like to use my LaunchImage as the background image of my home view (a pretty common practice to make the transition from 'loading' to 'loaded' look smooth). 我正在使用Xcode 5的资产目录,我想使用我的LaunchImage作为我的主视图的背景图像(这是一种非常常见的做法,使得从'加载'到'加载'的过渡看起来很流畅)。

I would like to use the same entry in the Asset Catalog to save space and not have to replicate the image in two different Image Sets. 我想在资产目录中使用相同的条目来节省空间,而不必在两个不同的图像集中复制图像。

However, calling: 但是,致电:

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

This is the (almost) complete list of the LaunchImage (excluding the iPad images with no status bar): 这是LaunchImage的(几乎)完整列表(不包括没有状态栏的iPad图像):

  • LaunchImage-568h@2x.png LaunchImage-568h@2x.png
  • LaunchImage-700-568h@2x.png LaunchImage-700-568h@2x.png
  • LaunchImage-700-Landscape@2x~ipad.png LaunchImage-700-Landscape@2x~ipad.png
  • LaunchImage-700-Landscape~ipad.png LaunchImage-700-景观〜ipad.png
  • LaunchImage-700-Portrait@2x~ipad.png LaunchImage-700-Portrait@2x~ipad.png
  • LaunchImage-700-Portrait~ipad.png LaunchImage-700-肖像〜ipad.png
  • LaunchImage-700@2x.png LaunchImage-700@2x.png
  • LaunchImage-Landscape@2x~ipad.png LaunchImage-Landscape@2x~ipad.png
  • LaunchImage-Landscape~ipad.png LaunchImage - 风景〜ipad.png
  • LaunchImage-Portrait@2x~ipad.png LaunchImage-Portrait@2x~ipad.png
  • LaunchImage-Portrait~ipad.png LaunchImage画像〜ipad.png
  • LaunchImage.png LaunchImage.png
  • LaunchImage@2x.png LaunchImage@2x.png
  • LaunchImage-800-667h@2x.png (iPhone 6) LaunchImage-800-667h@2x.png(iPhone 6)
  • LaunchImage-800-Portrait-736h@3x.png (iPhone 6 Plus Portrait) LaunchImage-800-Portrait-736h@3x.png(iPhone 6 Plus Portrait)
  • LaunchImage-800-Landscape-736h@3x.png (iPhone 6 Plus Landscape) LaunchImage-800-Landscape-736h@3x.png(iPhone 6 Plus横向)
  • LaunchImage-1100-Portrait-2436h@3x.png (iPhone X Portrait) LaunchImage-1100-Portrait-2436h@3x.png(iPhone X Portrait)
  • LaunchImage-1100-Landscape-2436h@3x.png (iPhone X Landscape) LaunchImage-1100-Landscape-2436h@3x.png(iPhone X Landscape)
- (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;
}

The LaunchImages are special, and aren't actually an asset catalog on the device. LaunchImages很特别,实际上并不是设备上的资产目录。 If you look using iFunBox/iExplorer/etc (or on the simulator, or in the build directory) you can see the final names, and then write code to use them - eg. 如果您使用iFunBox / iExplorer / etc(或在模拟器上或在构建目录中),您可以看到最终名称,然后编写代码以使用它们 - 例如。 for an iOS7-only iPhone-only project, this will set the right launch image: 对于仅限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]];

I put this into viewDidLoad. 我把它放到viewDidLoad中。

This isn't really ideal, it would be great if Apple would give us a nice API to do this. 这不是很理想,如果Apple能给我们一个很好的API来做这件事会很棒。

My app currently only supports iOS 7 and later. 我的应用程序目前仅支持iOS 7及更高版本。

This is how I reference the launch image from the asset catalog: 这是我从资产目录中引用启动图像的方式:

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

You can add more key value pairs if you want to support older iOS versions. 如果要支持较旧的iOS版本,可以添加更多键值对。

Here a category on UIImage based on the solution provided by Cherpak Evgeny above. 这里是基于上面Cherpak Evgeny提供的解决方案的UIImage类别。

UIImage+SplashImage.h : 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 : 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

@codeman's answer updated for Swift 1.2: @ 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

}

To call it, and to support rotation for iOS 8: 要调用它,并支持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)
    }

}

Just what I needed, thanks! 正是我需要的,谢谢!

I just wrote a general method to get the splash image name for iPhone and iPad (Landscape, Portrait), It worked for me, Hope It helps you as well. 我刚刚写了一个通用方法来获取iPhone和iPad(横向,纵向)的启动图像名称,它对我有用,希望它也可以帮到你。 I wrote this with help of other SO answers, thanks @Pichirichi for whole list. 我在其他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];
    }
 }
}

Other utility methods are 其他实用方法是

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

Swift version of Cherpak Evgeny's answer: Swift版本的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 ""
    }

Following @Pichirich's answer, I referenced my launchimage in InterfaceBuilder as: 按照@ Pichirich的回答,我在InterfaceBuilder中引用了我的launchimage:

"LaunchImage.png" “LaunchImage.png”

...and with Xcode 5.0.2, it's automatically plucking the appropriate image straight out of the Asset Catalog. ...并且使用Xcode 5.0.2,它会自动从资产目录中直接提取相应的图像。

This is what I'd expect - except for Apple's viciously nasty move of silently renaming "Default.png" to "LaunchImage.png" :) 这就是我所期望的 - 除了苹果公司将“Default.png”重命名为“LaunchImage.png”的恶意恶作剧:)

In the documentation there is clearly stated: 文件中有明确说明:

"Each set in an asset catalog has a name . You can use that name to programmatically load any individual image contained in the set. To load an image, call the UIImage:ImageNamed: method, passing the name of the set that contains the image." “资产目录中的每个集都有一个名称您可以使用该名称以编程方式加载集合中包含的任何单个图像。要加载图像,请调用UIImage:ImageNamed:方法,传递包含图像的集合的名称“。

Using Pichirichi's list helps to solve this inconsistency. 使用Pichirichi的列表有助于解决这种不一致。

One can easily access Launch image by one line of code. 可以通过一行代码轻松访问Launch image。

 UIImage *myAppsLaunchImage = [UIImage launchImage];

Please follow steps given below to achieve functionality depicted above. 请按照以下步骤操作,以实现上述功能。

Step 1. Extend UIImage class by creating a category & add following method to it. 步骤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;
}

Step 2. Above method should be working by adding following code also into same category of UIImage 步骤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;
}

I realize that this is not necessarily the best solution for everyone but the easiest (and least error-prone, IMHO) way to do this is by making a separate entry in your Images.xcassets catalog. 我意识到这不一定是每个人的最佳解决方案,但最简单(也是最不容易出错,恕我直言)的方法是在Images.xcassets目录中创建一个单独的条目。 I called it SplashImage . 我称之为SplashImage

When you go to add a new entry, make sure not to select "New Launch Image" as an option. 当您添加新条目时,请确保不要选择“新启动图像”作为选项。 Instead, select the generic "New Image Set". 而是选择通用的“新图像集”。 Next, open up the inspector and select the relevant options. 接下来,打开检查器并选择相关选项。 If you're building for only retina devices, as I was, you can select the following: 如果您只为视网膜设备构建,就像我一样,您可以选择以下内容:

图像检查员

This will leave you with four entries (iPhone 4S, iPhone 5(s,c), iPhone 6, and iPhone 6 Plus). 这将为您留下四个条目(iPhone 4S,iPhone 5(s,c),iPhone 6和iPhone 6 Plus)。

图片

The files corresponding the the images are as follows: 对应图像的文件如下:

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

Of course, after you've done this you can simply use [UIImage imageNamed:@"SplashImage"] 当然,完成后你可以简单地使用[UIImage imageNamed:@"SplashImage"]

With help of Pichirichi's answer I've implemented the following category (iOS 7+) : UIImage+AssetLaunchImage 在Pichirichi的回答的帮助下,我实现了以下类别(iOS 7 + ): UIImage + AssetLaunchImage

It's actually little more than generating name on the fly, but probably will be helpful. 它实际上只是动态生成名称,但可能会有所帮助。

Updated to latest Swift syntax (Swift 5) 更新到最新的Swift语法(Swift 5)

   func splashImageForOrientation(orientation: UIInterfaceOrientation) -> String? {

    var viewSize = screenSize
    var viewOrientation = "Portrait"
    if orientation.isLandscape {
        viewSize = CGSize(width: viewSize.height, height: viewSize.width)
        viewOrientation = "Landscape"
    }
    if let infoDict = Bundle.main.infoDictionary, let launchImagesArray = infoDict["UILaunchImages"] as? [Any] {
        for launchImage in launchImagesArray {
            if let launchImage = launchImage as? [String: Any], let nameString = launchImage["UILaunchImageName"] as? String, let sizeString = launchImage["UILaunchImageSize"] as? String, let orientationString = launchImage["UILaunchImageOrientation"] as? String {
                let imageSize = NSCoder.cgSize(for: sizeString)
                if imageSize.equalTo(viewSize) && viewOrientation == orientationString {
                    return nameString
                }
            }
        }
    }
    return nil
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM