web-dev-qa-db-ja.com

iOS 7 / Xcode 5:プログラムでデバイス起動画像にアクセスする

同じ画像リソースを複数の場所に配置せずに、アプリのLaunchImageをユニバーサルiOSアプリの背景として使用する方法はありますか?

Images.xcassetsLaunchImageファイルにアクセスできなかったため、2つの新しい画像セット「Background Portrait」と「Background Landscape」を作成しました(風景と同じセットにポートレート画像)。

この回避策は仕事をしますが、すべての画像をアプリに2回含めるのは嫌です。また、これには高い保守コストがかかります。

現在のデバイスのLaunchImageにアクセスする方法に関するアドバイスを歓迎します。

GCOLaunchImageTransition iOS <7のジョブを完了している必要があります。

41
Timm

起動イメージを2回含める必要なく使用できます。重要なのは、資産カタログを使用する場合、アプリバンドルに含まれる画像のファイル名は(一種の)標準化されており、元のファイルに名前を付けたものとは関係がない可能性があることです。

特に、LaunchImageイメージセットを使用する場合、アプリケーションバンドルに含まれるファイルの名前は次のようになります。

など。特に、それらはDefault.pngまたはそのバリエーションではないことに注意してください。それがファイルと呼ばれるものであっても。アセットカタログのwellsのいずれかにドロップすると、標準名でもう一方の端に表示されます。

したがって、アプリバンドルにそのようなファイルがないため、[UIImage imageNamed:@"Default"]は機能しません。ただし、[UIImage imageNamed:@"LaunchImage"]は機能します(iPhone Portrait 2xまたはiOS7以前 iPhone Portrait 1xのいずれかを満たした場合)。

ドキュメントには、UIImageimageNamed:メソッドが自動的に正しいバージョンを選択する必要があることが示されていますが、これは起動イメージ以外のイメージセットにのみ適用されると思います-少なくとも私は取得していません正しく動作するようになりました(ちょうど私が正しいことをしていないのかもしれません)。

したがって、正確な状況によっては、正しいファイル名を取得するために少し試行錯誤する必要があるかもしれません。シミュレータでアプリをビルドして実行すると、~/Library/Application Support/iPhone Simulatorの適切なサブディレクトリを常に見て、アプリバンドル内の実際のファイル名を確認できます。

ただし、ここでも重要な点は、イメージファイルの複製を含める必要がなく、Copy Bundle Resourcesビルドフェーズを調整する必要がないことです。

42
Matthew Burke

次のコードをコピーして貼り付けて、実行時にアプリの起動画像を読み込むことができます。

// Load launch image
NSString *launchImageName;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
    if ([UIScreen mainScreen].bounds.size.height == 480) launchImageName = @"[email protected]"; // iPhone 4/4s, 3.5 inch screen
    if ([UIScreen mainScreen].bounds.size.height == 568) launchImageName = @"[email protected]"; // iPhone 5/5s, 4.0 inch screen
    if ([UIScreen mainScreen].bounds.size.height == 667) launchImageName = @"[email protected]"; // iPhone 6, 4.7 inch screen
    if ([UIScreen mainScreen].bounds.size.height == 736) launchImageName = @"[email protected]"; // 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]];
56
John Erck

ほとんどの答えは、デバイスのタイプ、スケール、サイズなどに応じて画像名を作成する必要があります。しかし、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」を使用します)

41
Daniel Witurna

以下は、iOS 7.0以降でテストしたときの結果で、縦向きのみです。

3.5 inch screen: [email protected]
4.0 inch screen: [email protected]
4.7 inch screen: [email protected]
5.5 inch screen: [email protected]
iPad2          : LaunchImage-700-Portrait~ipad.png
Retina iPads   : LaunchImage-700-Portrait@2x~ipad.png
10
ZYiOS

Swift優れたバージョン answer Daniel Witurnaによるバージョン。既知のすべてのデバイスタイプまたは向きのリストをチェックする必要はありません。

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
}
9
Simo

Info.plistバンドルには、起動イメージの名前などの起動イメージ情報が含まれます。

Objective-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
}
5
Lavare

実行時に起動イメージ名を取得するためのSwiftの簡潔な関数:

func launchImageName() -> String {
    switch (UI_USER_INTERFACE_IDIOM(), UIScreen.mainScreen().scale, UIScreen.mainScreen().bounds.size.height) {
        case (.Phone, _, 480): return "[email protected]"
        case (.Phone, _, 568): return "[email protected]"
        case (.Phone, _, 667): return "[email protected]"
        case (.Phone, _, 736): return "[email protected]"
        case (.Pad, 1, _): return "LaunchImage-700-Portrait~ipad.png"
        case (.Pad, 2, _): return "LaunchImage-700-Portrait@2x~ipad.png"
        default: return "LaunchImage"
    }
}
2
Jason Cabot

マシュー・バークの答えは正解です。以下は、iOS9/Xcode7でこれを機能させるために使用しているコードで、iOS7以上のアプリを作成し、iPhoneとiPadでランドスケープを許可しています。

まず、もう少し詳しく説明します:iOS8/Xcode6では、ストーリーボードの起動画面ファイルを使用している場合、アプリの起動時に、アプリはその起動画面ファイルの2つの画像(ポートレート1つ、風景1つ)を正しい解像度で作成しますデバイスとファイルパスからそのイメージを取得できました。 (Library/LaunchImageフォルダーに保存されたと思われます)。

ただし、iOS9/XCode 7では、このイメージはもう作成されません(スナップショットはスナップショットフォルダーで取得されますが、常に変化するわかりにくい名前が付けられています)ので、コードのどこかでLaunchImageを使用する場合(アプリのシンニングのために、できればアセットカタログを介して)Launch Image Sourceを使用する必要があります。さて、マシュー・バークが説明しているように、次のことだけではそのイメージに到達することはできません。

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/DeviceGur まだ最新のデバイス(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 = "[email protected]"
        let HD40 = "LaunchImage-700-568h@2x"
        let HD47 = "[email protected]"
        var HD55 = "[email protected]"
        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 = "[email protected]"
            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
    }
    
1
guido

以下は、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; }
1
Saikiran K

これがコードを介したアクセスで何を意味するのかはわかりません。ただし、「プロジェクト->ターゲット->ビルドフェーズ->バンドルリソースのコピー」を選択した場合は、「+」をクリックし、「その他を追加」をクリックしてImages.xcassets-> LaunchImage.launchimageに移動し、使用するpngを選択します「開く」をクリックします。これで、[UIImage imageNamed:@"Default"];のような画像を使用できます

1
Peter Segerblom
 if (IS_IPHONE_4_OR_LESS) {
    self.imageView.image = [UIImage imageNamed:@"[email protected]"];
}
else if (IS_IPHONE_5){
     self.imageView.image = [UIImage imageNamed:@"[email protected]"];
}
else if (IS_IPHONE_6){
     self.imageView.image = [UIImage imageNamed:@"[email protected]"];
}
else if (IS_IPHONE_6P){
      self.imageView.image = [UIImage imageNamed:@"[email protected]"];
}
1
shweta sharma

デバイスを決定する必要がある場合は、次のコードを使用します(少し速くて汚いですが、トリックを行います)

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");
    }
}
1
Roland Keesom

ダニエルによる 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
0
apouche

Images.xcassetsを作成したら、LaunchImageの名前をDefaultに変更します。

IOS5およびiOS6をサポートしている場合、これにより多くのトラブルを回避できます。

「フォルダ」/カテゴリの実際の名前は、ビルド時にアセットに続きます。他のすべてはマシュー・バークが言ったことに真実です;)

0
Danoli3

プロジェクトに新しいグループを作成します。物理ディレクトリを使用しません。 LaunchImage.launchimageから直接、起動画像をそのグループにインポートします。ボイラ。

0
QED