Reputation: 139
I tried to make a SwiftUI class that conforms to UIViewRepresentable and implements makeUIView and updateUIView. But not able to complete it.Here is code :
Code:
struct ImagePicker : UIViewRepresentable {
@Binding var image: UIImage
class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
@Binding var image: UIImage
init(image: Binding<UIImage>) {
$image = image
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let possibleImage = info[.editedImage] as? UIImage {
image = possibleImage
} else if let possibleImage = info[.originalImage] as? UIImage {
image = possibleImage
} else {
}
}
}
func makeCoordinator() -> Coordinator {
return Coordinator(image: $image)
}
func makeUIView(context: UIViewRepresentableContext<ImagePicker>) -> UIImageView {
let imageview = UIImageView()
let picker = UIImagePickerController()
picker.delegate = context.coordinator
return imageview
}
func updateUIView(_ uiView: UIImageView,
context: UIViewRepresentableContext<ImagePicker>) {
uiView.image = image
}
}
I tried imagePicker as control but unable to use.
Upvotes: 6
Views: 7087
Reputation: 186
2023 version
import SwiftUI
import PhotosUI
struct TestImagePicker: View {
//MARK: - Properties
@State private var selectedItems: [PhotosPickerItem] = []
@State private var imageData: [PhotosPickerItem: Data] = [:]
//MARK: - Body
var body: some View {
VStack {
PhotosPicker(
selection: $selectedItems,
maxSelectionCount: 2,
matching: .images,
photoLibrary: .shared()
) {
Text("Choose Photos from Gallery")
}
.onChange(of: selectedItems) { newValue in
for item in newValue {
Task {
if let data = try? await item.loadTransferable(type: Data.self) {
imageData[item] = data
}
}
}
}
ScrollView(.horizontal) {
HStack {
ForEach(Array(imageData.keys), id: \.self) { item in
if let data = imageData[item], let uiImage = UIImage(data: data) {
Image(uiImage: uiImage)
.resizable()
.scaledToFit()
.frame(width: 250, height: 250)
}
}
}
}
}
.padding()
}
}
Upvotes: 1
Reputation: 10299
SwiftUI is finally getting its own native photo picker view in iOS 16. The PhotosPicker view supports all the common functionalities that PHPickerViewController provide like single and multiple selections, asset type filtering, and album switching are all included.
import SwiftUI
import PhotosUI
struct ContentView: View {
//MARK: - Properties
//@State private var selectedItem: [PhotosPickerItem] = [PhotosPickerItem]() // use to select multiple images from gallery
@State private var selectedItem: PhotosPickerItem? = nil
@State private var selectedImageData: Data? = nil
//MARK: - Body
var body: some View {
VStack {
PhotosPicker(
selection: $selectedItem,
// maxSelectionCount: 2, //set max selection from gallery
matching: .images,
photoLibrary: .shared()
) {
Text("Choose Photos from Gallery")
.frame(width: 350, height: 50)
.background(Capsule().stroke(lineWidth: 2))
}
.onChange(of: selectedItem) { newValue in
Task { // Incase of multiple selection newValue is of array type
if let data = try? await newValue?.loadTransferable(type: Data.self) {
selectedImageData = data
}
}
}
if let selectedImageData, let uiImage = UIImage(data: selectedImageData) {
Image(uiImage: uiImage)
.resizable()
.scaledToFit()
.frame(width: 250, height: 250)
.overlay(
RoundedRectangle(cornerRadius: 16).stroke(Color.yellow, lineWidth: 8)
)
}
}
.padding()
}
}
Sample ss
Upvotes: 4
Reputation: 182
Pls try This one
Code:
import SwiftUI
struct OpenGallary: UIViewControllerRepresentable {
let isShown: Binding<Bool>
let image: Binding<Image?>
class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
let isShown: Binding<Bool>
let image: Binding<Image?>
init(isShown: Binding<Bool>, image: Binding<Image?>) {
self.isShown = isShown
self.image = image
}
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let uiImage = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
self.image.wrappedValue = Image(uiImage: uiImage)
self.isShown.wrappedValue = false
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
isShown.wrappedValue = false
}
}
func makeCoordinator() -> Coordinator {
return Coordinator(isShown: isShown, image: image)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<OpenGallary>) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: UIImagePickerController,
context: UIViewControllerRepresentableContext<OpenGallary>) {
}
}
the picker is displayed right on top of the view, without transition the selected image appears without any sort of animation, and replaces the Show image picker button
After that create display view in which you can call show this imagePicker
struct ContentView: View {
@State var showImagePicker: Bool = false
@State var image: Image?
var body: some View {
ZStack {
VStack {
Button(action: {
withAnimation {
self.showImagePicker.toggle()
}
}) {
Text("Show image picker")
}
image?.resizable().frame(width: 100, height: 100)
}
if (showImagePicker) {
OpenGallary(isShown: $showImagePicker, image: $image)
}
}
}
}
Upvotes: 1
Reputation: 23053
I am using presentationMode
here, to check for the view that is it presenting or not?
By using this you can dismiss()
the UIImagePickerController
.
Sample code for SwiftUI preview:
import SwiftUI
struct ContentView: View {
@State var isShowPicker: Bool = false
@State var image: Image? = Image("placeholder")
var body: some View {
NavigationView {
ZStack {
VStack {
image?
.resizable()
.scaledToFit()
.frame(height: 320)
Button(action: {
withAnimation {
self.isShowPicker.toggle()
}
}) {
Image(systemName: "photo")
.font(.headline)
Text("IMPORT").font(.headline)
}.foregroundColor(.black)
Spacer()
}
}
.sheet(isPresented: $isShowPicker) {
ImagePicker(image: self.$image)
}
.navigationBarTitle("Pick Image")
}
}
}
struct ImagePicker: UIViewControllerRepresentable {
@Environment(\.presentationMode)
var presentationMode
@Binding var image: Image?
class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
@Binding var presentationMode: PresentationMode
@Binding var image: Image?
init(presentationMode: Binding<PresentationMode>, image: Binding<Image?>) {
_presentationMode = presentationMode
_image = image
}
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let uiImage = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
image = Image(uiImage: uiImage)
presentationMode.dismiss()
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
presentationMode.dismiss()
}
}
func makeCoordinator() -> Coordinator {
return Coordinator(presentationMode: presentationMode, image: $image)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: UIImagePickerController,
context: UIViewControllerRepresentableContext<ImagePicker>) {
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
ContentView()
}
}
}
Upvotes: 14