10
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

iOS強化月間 - iOSアプリ開発の知見を共有しよう -

【iOS】アプリアイコンをさくっと作成する方法

Last updated at Posted at 2023-10-01

アプリのアイコンが付いていないとコードを書く気が出ないという時ってありますよね。そんなときに、とりあえずそれっぽいアイコンをさくっく作成する方法のご紹介です。
image.png
↑ やる気がでないやつ

Android版のアイコン作成アプリもつくってみました。(2023/10/9)
https://qiita.com/yuppejp/items/353d312492681c8244a8

アプリアイコンの作成の流れ

  1. アイコン画像を表示するViewの作成
  2. Viewのスナップショットをファイルに保存(1024x1024ピクセル、透過PNG)
  3. 画像ファイルをXcodeのAppIconアセットに設定

アイコン画像を表示するViewの作成

SF Symbolesを使って適当なアイコンをViewに表示して、背景色にグラデーションをかけるだけです。背景色にグラデーションを付けるのはiOS16から使えます。
image.png

AppIconView.swift
struct AppIconView: View {
    var systemName: String  // SF Symbolsの名前
    var color: AnyGradient  // グラデーションカラー(iOS16〜)
    
    var body: some View {
        GeometryReader { geometry in
            ZStack {
                Rectangle()
                    .fill(color)
                Image(systemName: systemName)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .foregroundColor(.white)
                    .padding(geometry.size.width * 0.15) // 余白を多めにとる(全体の15%程度)
            }
        }
    }
}

#Preview {
    VStack {
        AppIconView(systemName: "pencil.and.outline", color: Color.orange.gradient)
            .frame(width: 150, height: 150)
        AppIconView(systemName: "tram", color: Color.green.gradient)
            .frame(width: 150, height: 150)
        AppIconView(systemName: "sailboat.fill", color: Color.blue.gradient)
            .frame(width: 150, height: 150)
    }
}

Viewのスナップショットをファイルに保存

ファイル保存用のボタンを設置し、UIViewControllerに拡張したsnapshotメソッドでレンダリングします。このとき背景透過になるようにbackgroundColorを .clear に設定します。画像ファイルはカメラロールに保存されます(シミュレーター時のファイルパスは後述)。

アイコンや色を変えるUIは今回用意していなので、コード上のiconNameとiconColorを直接書き換えてください。

ContentView.swift
import SwiftUI
import Photos

struct ContentView: View {
    var iconName = "pencil.and.outline"
    var iconColor = Color.orange.gradient
    @State private var showAlert = false
    @State private var alertMessage = ""
    
    var body: some View {
        VStack {
            Spacer()
            AppIconView(systemName: iconName, color: iconColor)
                .frame(width: 300, height: 300)
            Text(iconName)
            Spacer()
            Button("Save Image") {
                saveToPhotos()
            }
        }
        .alert(isPresented: $showAlert) {
            Alert(title: Text("Result"), message: Text(alertMessage), dismissButton: .default(Text("OK")))
        }
    }
    
    private func saveToPhotos() {
        DispatchQueue.main.async {
            let viewSize = CGSize(width: 1024, height: 1024)
            
            let hostingController = UIHostingController(
                rootView: AppIconView(systemName: iconName, color: iconColor)
                    .frame(width: viewSize.width, height: viewSize.height)
                    .offset(CGSize(width: 0, height: -12))
                    .background(iconColor)
            )
            
            hostingController.view.frame = CGRect(origin: .zero, size: viewSize)
            hostingController.view.backgroundColor = .clear
            
            let image = hostingController.snapshot(viewSize: viewSize)
            
            // PNGとしてカメラロールに保存
            if let data = image.pngData() {
                PHPhotoLibrary.shared().performChanges({
                    let creationRequest = PHAssetCreationRequest.forAsset()
                    creationRequest.addResource(with: .photo, data: data, options: nil)
                }) { success, error in
                    if let error = error {
                        alertMessage = "Error saving the image: \(error)"
                        showAlert = true
                    } else {
                        alertMessage = "Success saving image"
                        showAlert = true
                    }
                }
            }
        }
    }
}

extension UIViewController {
    func snapshot(viewSize: CGSize) -> UIImage {
        let rendererFormat = UIGraphicsImageRendererFormat.default()
        rendererFormat.scale = 1
        let renderer = UIGraphicsImageRenderer(size: viewSize, format: rendererFormat)
        
        let image = renderer.image { _ in
            let context = UIGraphicsGetCurrentContext()!
            context.interpolationQuality = .high
            view.drawHierarchy(in: CGRect(origin: .zero, size: viewSize), afterScreenUpdates: true)
        }
        
        return image
    }
}

#Preview {
    ContentView()
}

シミュレーターで実行している場合の保存場所

XcodeのiOSエミュレータでアプリを実行すると、アプリの画像ファイルはMac上の特定のディレクトリに保存されます。エミュレータの内部ファイルシステムにアクセスするには、以下のディレクトリパスをFinderで参照することができます:

~/Library/Developer/CoreSimulator/Devices/[DEVICE_ID]/data/Media/DCIM/100APPLE/

ここの、[DEVICE_ID]は実行中のエミュレータデバイスの一意のIDです。
DEVICE_IDを調べる手順:

  1. Xcodeの"Window" メニューから "Devices and Simulators" を選択します。
  2. 左側のペインで実行中のシミュレータデバイスを選択します。
  3. 右ペインの上部に表示されるIdentifierがデバイスIDです。
    貼り付けた画像_2023_10_09_12_15.png
    Finderで表示した例:
    image.png
    IMG_nnnn.PNGという感じでファイルが作成されます。

画像ファイルをXcodeのAppIconアセットに設定

拡張子が大文字だとXcodeが警告してくるので、小文字の .png に変更しておきます。あとはXcodeのAppIconアセットに画像ファイルをDrang&Dropしたら完了です。
image.png

完成サンプル

いい感じにできました。
image.png

おしまい!

サンプルコード一式

Android版はこちら

【Android】アプリアイコンをさくっと作成する方法

10
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?