Skip to content

Instantly share code, notes, and snippets.

@MarcoEidinger
Created June 28, 2022 00:08
Show Gist options
  • Save MarcoEidinger/a5f44d79f0dfc6619db5126e903903f9 to your computer and use it in GitHub Desktop.
Save MarcoEidinger/a5f44d79f0dfc6619db5126e903903f9 to your computer and use it in GitHub Desktop.
Working example of using PhotosPicker in a SwiftUI application (verified on Xcode 14 Beta 2 and iOS 16 simulator)
import SwiftUI
struct CircularProfileImage: View {
let imageState: ProfileModel.ImageState
var body: some View {
ProfileImage(imageState: imageState)
.frame(width: 100, height: 100)
.clipShape(Circle())
.background {
Circle().fill(
LinearGradient(colors: [.yellow, .orange], startPoint: .top, endPoint: .bottom)
)
}
}
}
import SwiftUI
struct ContentView: View {
@State var viewModel: ProfileModel = .init()
var body: some View {
EditableCircularProfileImage(viewModel: viewModel)
}
}
import PhotosUI
import SwiftUI
struct EditableCircularProfileImage: View {
@ObservedObject var viewModel: ProfileModel
var body: some View {
CircularProfileImage(imageState: viewModel.imageState)
.overlay(alignment: .bottomTrailing) {
PhotosPicker(selection: $viewModel.imageSelection, matching: .images, photoLibrary: .shared()) {
Image(systemName: "pencil.circle.fill")
.symbolRenderingMode(.multicolor)
.font(.system(size: 30))
.foregroundColor(.accentColor)
}
}
.buttonStyle(.borderless)
}
}
import SwiftUI
@main
struct MyPhotoAppApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
import SwiftUI
struct ProfileImage: View {
let imageState: ProfileModel.ImageState
var body: some View {
switch imageState {
case .empty:
Image(systemName: "person.fill")
.font(.system(size: 40))
.foregroundColor(.white)
case .loading:
ProgressView()
case let .success(image):
image.resizable().scaledToFit()
case .failure:
Image(systemName: "exclamationmark.triangle.fill")
.font(.system(size: 40))
.foregroundColor(.white)
}
}
}
import PhotosUI
import SwiftUI
class ProfileModel: ObservableObject {
enum ImageState {
case empty, loading(Progress), success(Image), failure(Error)
}
@Published private(set) var imageState: ImageState = .empty
@Published var imageSelection: PhotosPickerItem? {
didSet {
if let imageSelection {
let progress = loadTransferable(from: imageSelection)
imageState = .loading(progress)
} else {
imageState = .empty
}
}
}
private func loadTransferable(from imageSelection: PhotosPickerItem) -> Progress {
return imageSelection.loadTransferable(type: Data.self) { result in
DispatchQueue.main.async {
guard imageSelection == self.imageSelection else { return }
switch result {
case let .success(data?):
guard let uiImage = UIImage(data: data) else {
self.imageState = .empty
return
}
self.imageState = .success(Image(uiImage: uiImage))
case .success(.none):
self.imageState = .empty
case let .failure(error):
self.imageState = .failure(error)
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment