Last active
June 15, 2022 15:52
-
-
Save mattyoung/de81ee00aec769d41f7e3fd892bb40b4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // 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