Skip to content

Instantly share code, notes, and snippets.

@mattyoung
Last active June 15, 2022 15:52
Show Gist options
  • Select an option

  • Save mattyoung/de81ee00aec769d41f7e3fd892bb40b4 to your computer and use it in GitHub Desktop.

Select an option

Save mattyoung/de81ee00aec769d41f7e3fd892bb40b4 to your computer and use it in GitHub Desktop.
//
// AppIconMakerDemo.swift
// SwiftUI40
//
// Created by Mateo on 6/13/22.
//
// base from this:
// https://www.youtube.com/watch?v=iNCXmq99mjw
// Note:
// You must set the key in your info:
// NSPhotoLibraryAddUsageDescription
import SwiftUI
import PhotosUI
struct AppIconMaker<IconView: View>: View {
let icon: IconView
@State private var showSaveAlert = false
@State private var saveIsSuccessful = true
var iconView: some View {
Color.clear
.aspectRatio(1, contentMode: .fit)
// make the icon exactly 1024x1024
// this create 342x342
// Scale is points / pixels, set the image size to exactly 1024 pixel
// .frame(width: 1024 / UIScreen.main.scale)
// this create 1024x1024 (not sure if this is correct, but it works out)
.frame(width: 1024)
.overlay {
icon
}
}
var body: some View {
VStack {
ZStack {
LinearGradient(colors: [.green, .yellow, .orange, .red, .purple, .blue], startPoint: .top, endPoint: .bottomTrailing)
.ignoresSafeArea()
.overlay(alignment: .top) {
VStack {
Text("App Icon Maker")
.font(.largeTitle.bold())
.foregroundColor(.mint)
.shadow(color: .red, radius: 5)
Text("Press \"Save to Image\" button to save the icon image to the photo album")
.multilineTextAlignment(.center)
.font(.footnote)
.padding(.horizontal)
.frame(width: UIScreen.main.bounds.width)
}
}
iconView
.border(.mint, width: 8)
.scaleEffect(UIScreen.main.bounds.width / 1024) // try to fit on screen
let _ = print(UIScreen.main.bounds.width)
}
Button {
let renderer = ImageRenderer(content: iconView)
UIImpactFeedbackGenerator(style: .medium).impactOccurred()
showSaveAlert = true
if let image = renderer.uiImage {
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
saveIsSuccessful = true
} else {
saveIsSuccessful = false
}
} label: {
Label("Save to Image", systemImage: "photo.on.rectangle.angled")
.frame(maxWidth: .infinity, alignment: .center)
}
.padding(.horizontal)
.buttonStyle(.borderedProminent)
.controlSize(.large)
}
// can only have one .alert modifier!
.alert(isPresented: $showSaveAlert) {
alertView
}
}
var alertView: Alert {
saveIsSuccessful ?
Alert(
title: Text("Success"),
message: Text("The app icon is saved to photo album.")
)
:
Alert(
title: Text("Failure"),
message: Text("The app icon save to photo album failed.")
)
}
}
struct AppIconMakerDemo: View {
var iconView: some View {
createAwardView(title: "100% Accurate Archer", date: .now)
}
var body: some View {
AppIconMaker(icon: iconView)
}
// all sizing parameters must be scale to the 1024x1024 pixel square
func createAwardView(title: String, date: Date) -> some View {
ZStack {
Color.yellow
VStack(spacing: 0) {
Spacer()
Image(systemName: "figure.archery")
.resizable()
.aspectRatio(1, contentMode: .fit)
.frame(width: 1024)
.minimumScaleFactor(0.1)
.padding()
.shadow(color: .red, radius: 25)
Spacer()
VStack {
// must size thing large in 1024x1024 pixels square size
Text(title)
.font(.system(size: 90, weight: .heavy, design: .rounded))
// the dateTime .month() format is correct on screen
// but when feed through `ImageRenderer`, it appears it's using a different locale so
// the month instead of "June", it's "M06"
// Text(date, format: .dateTime.day().month(.wide).year())
// this way its formatted correctly, but I don't want the time part
Text(date.formatted())
.font(.system(size: 80))
}
.offset(x: 0, y: -10)
}
}
}
}
struct ImageRendererDemo_Previews: PreviewProvider {
static var previews: some View {
AppIconMakerDemo()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment