如何在Swift中同时使用相机和照片库创建UIImagePickerController

52

我使用UIImagePickerController通过iPhone相机拍摄照片。

我想同时展示“拍照”和“选择照片”功能。

我的代码

imagePicker =  UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .camera
//imagePicker.sourceType = .PhotoLibrary
presentViewController(imagePicker, animated: true, completion: nil)

我尝试同时使用imagePicker.sourceType = .CameraimagePicker.sourceType = .PhotoLibrary来实现这个功能,但是它不起作用...

谢谢


官方文档:https://developer.apple.com/library/content/documentation/AudioVideo/Conceptual/CameraAndPhotoLib_TopicsForIOS/Introduction/Introduction.html#//apple_ref/doc/uid/TP40010405-SW1 - Ferran Maylinch
9个回答

83

升级到Swift 5+

导入UIImagePickerControllerDelegate并创建一个变量来分配UIImagePickerController var imagePicker = UIImagePickerController()并设置imagePicker.delegate = self

创建一个操作表来显示“相机”和“照片库”的选项。

在您的按钮点击操作中:

/// Button action
@IBAction func btnChooseImageOnClick(_ sender: UIButton) {
    
    let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
    alert.addAction(UIAlertAction(title: "Take Photo", style: .default, handler: { _ in
        self.openCamera()
    }))
    
    alert.addAction(UIAlertAction(title: "Choose Photo", style: .default, handler: { _ in
        self.openGallary()
    }))
    
    alert.addAction(UIAlertAction.init(title: "Cancel", style: .cancel, handler: nil))
    
    //If you want work actionsheet on ipad then you have to use popoverPresentationController to present the actionsheet, otherwise app will crash in iPad
    switch UIDevice.current.userInterfaceIdiom {
    case .pad:
        alert.popoverPresentationController?.sourceView = sender
        alert.popoverPresentationController?.sourceRect = sender.bounds
        alert.popoverPresentationController?.permittedArrowDirections = .up
    default:
        break
    }
    
    self.present(alert, animated: true, completion: nil)
}

/// Open the camera
func openCamera() {
    if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerController.SourceType.camera)){
        imagePicker.sourceType = UIImagePickerController.SourceType.camera
        //If you dont want to edit the photo then you can set allowsEditing to false
        imagePicker.allowsEditing = true
        imagePicker.delegate = self
        self.present(imagePicker, animated: true, completion: nil)
    }
    else{
        let alert  = UIAlertController(title: "Warning", message: "You don't have camera", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
        self.present(alert, animated: true, completion: nil)
    }
}

/// Choose image from camera roll
func openGallary() {
    imagePicker.sourceType = UIImagePickerController.SourceType.photoLibrary
    // If you don't want to edit the photo then you can set allowsEditing to false
    imagePicker.allowsEditing = true
    imagePicker.delegate = self
    self.present(imagePicker, animated: true, completion: nil)
}

委托实现 - UIImagePickerControllerDelegate,UINavigationControllerDelegate:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    // Get the image from the info dictionary.
    if let editedImage = info[.editedImage] as? UIImage {
        self.imgProfile.image = editedImage
    }
    
    // Dismiss the UIImagePicker after selection
    picker.dismiss(animated: true, completion: nil)
}

func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
    picker.isNavigationBarHidden = false
    self.dismiss(animated: true, completion: nil)
}

下载Swift示例项目,SwiftUI


1
感谢您的回答,UIActionSheet在iPad上崩溃了,如何修复? - Coucou
1
解决方案很好,但我发现了一个基于场景的错误,我在imagePickerControllerDidCancel函数(来自您的GitHub项目)下添加了“imagePicker.dismiss(animated: true, completion: nil)”,并且每次在第一次运行或重新启动时,尝试按照以下步骤重现错误:1.选择个人资料>拍照 2.点击取消(不要拍照) 3.现在再次点击选择个人资料>选择照片 4.您将看到imagePicker的取消按钮已消失。 请记住通过从内存中清除它来重新启动应用程序以重现此错误。 - Saathwik
1
@Saathwik 你是对的。问题确实存在,我已经修复了它。 请在你的项目中替换以下代码:func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { picker.isNavigationBarHidden = false self.dismiss(animated: true, completion: nil) } - anas.p
在 Github 项目中问题已经解决,感谢 @Saathwik。 - anas.p
1
你的答案包含了很多错误,请修正它们。 - Gargo
显示剩余2条评论

60

Swift 5 +:

使用相机和图库的操作表:

//MARK:- Image Picker
    @IBAction func imagePickerBtnAction(selectedButton: UIButton)
    {

        let alert = UIAlertController(title: "Choose Image", message: nil, preferredStyle: .actionSheet)
        alert.addAction(UIAlertAction(title: "Camera", style: .default, handler: { _ in
            self.openCamera()
        }))

        alert.addAction(UIAlertAction(title: "Gallery", style: .default, handler: { _ in
            self.openGallery()
        }))

        alert.addAction(UIAlertAction.init(title: "Cancel", style: .cancel, handler: nil))

        self.present(alert, animated: true, completion: nil)
    }

相机图像选择器功能:

func openCamera()
{
    if UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.camera) {
        let imagePicker = UIImagePickerController()
        imagePicker.delegate = self
        imagePicker.sourceType = UIImagePickerController.SourceType.camera
        imagePicker.allowsEditing = false
        self.present(imagePicker, animated: true, completion: nil)
    }
    else
    {
        let alert  = UIAlertController(title: "Warning", message: "You don't have camera", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
        self.present(alert, animated: true, completion: nil)
    }
}
相册图片选择器功能:
 func openGallery()
{
    if UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.photoLibrary){
        let imagePicker = UIImagePickerController()
        imagePicker.delegate = self
        imagePicker.allowsEditing = true
        imagePicker.sourceType = UIImagePickerController.SourceType.photoLibrary
        self.present(imagePicker, animated: true, completion: nil)
    }
    else
    {
        let alert  = UIAlertController(title: "Warning", message: "You don't have permission to access gallery.", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
        self.present(alert, animated: true, completion: nil)
    }
}

ImagePicker代理:

//MARK:-- ImagePicker delegate
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    if let pickedImage = info[.originalImage] as? UIImage {
        // imageViewPic.contentMode = .scaleToFill
    }
    picker.dismiss(animated: true, completion: nil)
}

14

设置代理:

UIImagePickerControllerDelegate,UINavigationControllerDelegate

拿一个ImageView,这样我们就可以显示选定/捕获的图像:

@IBOutlet weak var imageViewPic: UIImageView!
使用设备相机捕获新图像的方法如下:
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera) {
        let imagePicker = UIImagePickerController()
        imagePicker.delegate = self
        imagePicker.sourceType = UIImagePickerControllerSourceType.camera
        imagePicker.allowsEditing = false
        self.present(imagePicker, animated: true, completion: nil)
    }

从画廊中选择照片:

if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.photoLibrary){
        let imagePicker = UIImagePickerController()
        imagePicker.delegate = self
        imagePicker.allowsEditing = true
        imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary
        self.present(imagePicker, animated: true, completion: nil)
    }

这是委托方法:

     //MARK: - ImagePicker delegate
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
       // imageViewPic.contentMode = .scaleToFill
        imageViewPic.image = pickedImage
    }
    picker.dismiss(animated: true, completion: nil)
}

需要在info.plist中设置访问相机和照片的权限,例如:


<key>NSCameraUsageDescription</key>
<string>This app will use camera</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>You can select photo</string>

输入图像描述

100%可行并已测试


1
图书馆访问警告未出现。 - Jatin Vashisht

3

在故事板中创建视图控制器,添加按钮和图片

在视图控制器中添加UIImagePickerControllerDelegate、UINavigationControllerDelegate协议

相机操作按钮输入以下代码

let imagePickerController = UIImagePickerController()
    imagePickerController.delegate = self
    let actionsheet = UIAlertController(title: "Photo Source", message: "Choose A Sourece", preferredStyle: .actionSheet)
    actionsheet.addAction(UIAlertAction(title: "Camera", style: .default, handler: { (action:UIAlertAction)in
        if UIImagePickerController.isSourceTypeAvailable(.camera){
            imagePickerController.sourceType = .camera
            self.present(imagePickerController, animated: true, completion: nil)
        }else
        {
            print("Camera is Not Available")
        }



    }))
    actionsheet.addAction(UIAlertAction(title: "Photo Library", style: .default, handler: { (action:UIAlertAction)in
        imagePickerController.sourceType = .photoLibrary
        self.present(imagePickerController, animated: true, completion: nil)
    }))
    actionsheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
    self.present(actionsheet,animated: true, completion: nil)

在视图控制器中添加以下功能。
 func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    let image = info[UIImagePickerControllerOriginalImage] as! UIImage
    imageView.image = image
    picker.dismiss(animated: true, completion: nil)
    }
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
    picker.dismiss(animated:  true, completion: nil)
    }
}

在info.plist中添加一行,内容为:
 Privacy - Photo Library Usage Description
Privacy - Camera Usage Description

3

我创建了这个精美的项目,用这四行代码,你可以从相机或图库获取图像,并使用一行代码应用美丽的滤镜,就像这样:

let picker = PickerController()
picker.applyFilter = true // to apply filter after selecting the picture by default false
picker.selectImage(self){ image in
    // Use the picture
}

图片描述输入位置

这是该项目的链接。


2
//MARK:- Camera and Gallery

    func showActionSheet(){

        //Create the AlertController and add Its action like button in Actionsheet
        let actionSheetController: UIAlertController = UIAlertController(title: NSLocalizedString("Upload Image", comment: ""), message: nil, preferredStyle: .actionSheet)
        actionSheetController.view.tintColor = UIColor.black
        let cancelActionButton: UIAlertAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel) { action -> Void in
            print("Cancel")
        }
        actionSheetController.addAction(cancelActionButton)

        let saveActionButton: UIAlertAction = UIAlertAction(title: NSLocalizedString("Take Photo", comment: ""), style: .default)
        { action -> Void in
            self.camera()
        }
        actionSheetController.addAction(saveActionButton)

        let deleteActionButton: UIAlertAction = UIAlertAction(title: NSLocalizedString("Choose From Gallery", comment: ""), style: .default)
        { action -> Void in
            self.gallery()
        }
        actionSheetController.addAction(deleteActionButton)
        self.present(actionSheetController, animated: true, completion: nil)
    }

    func camera()
    {
        let myPickerControllerCamera = UIImagePickerController()
        myPickerControllerCamera.delegate = self
        myPickerControllerCamera.sourceType = UIImagePickerController.SourceType.camera
        myPickerControllerCamera.allowsEditing = true
        self.present(myPickerControllerCamera, animated: true, completion: nil)

    }

    func gallery()
    {

        let myPickerControllerGallery = UIImagePickerController()
        myPickerControllerGallery.delegate = self
        myPickerControllerGallery.sourceType = UIImagePickerController.SourceType.photoLibrary
        myPickerControllerGallery.allowsEditing = true
        self.present(myPickerControllerGallery, animated: true, completion: nil)

    }


    //MARK:- ***************  UIImagePickerController delegate Methods ****************

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

        // The info dictionary may contain multiple representations of the image. You want to use the original.
        guard let selectedImage = info[.originalImage] as? UIImage else {
            fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
        }

        // Set photoImageView to display the selected image.
        imageUserProfile.image = selectedImage

        // Dismiss the picker.
        dismiss(animated: true, completion: nil)
    }

在iOS 13上,只有这个回答对我起作用了。 - Torben545
@Torben545:我总是只放置已执行的代码。 - Davender Verma

0

这将创建一个可重用的类,当你的图片、按钮等被点击时,它将显示一个操作表。

import Foundation
import UIKit


class CameraHandler: NSObject{
    static let shared = CameraHandler()
    
    fileprivate var currentVC: UIViewController!
    
    //MARK: Internal Properties
    var imagePickedBlock: ((UIImage) -> Void)?

    func camera()
    {
        if UIImagePickerController.isSourceTypeAvailable(.camera){
            let myPickerController = UIImagePickerController()
            myPickerController.delegate = self
            myPickerController.allowsEditing = true
            myPickerController.sourceType = .camera
            currentVC.present(myPickerController, animated: true, completion: nil)
        }
        
    }
    
    func photoLibrary()
    {
        
        if UIImagePickerController.isSourceTypeAvailable(.photoLibrary){
            let myPickerController = UIImagePickerController()
            myPickerController.delegate = self
            myPickerController.allowsEditing = true
            myPickerController.sourceType = .photoLibrary
            currentVC.present(myPickerController, animated: true, completion: nil)
        }
        
    }
    
    func showActionSheet(vc: UIViewController) {
        currentVC = vc
        let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
        
        actionSheet.addAction(UIAlertAction(title: "Camera", style: .default, handler: { (alert:UIAlertAction!) -> Void in
            self.camera()
        }))
        
        actionSheet.addAction(UIAlertAction(title: "Gallery", style: .default, handler: { (alert:UIAlertAction!) -> Void in
            self.photoLibrary()
        }))
        
        actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
        
        vc.present(actionSheet, animated: true, completion: nil)
    }
    
}


extension CameraHandler: UIImagePickerControllerDelegate, UINavigationControllerDelegate{
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    // The info dictionary may contain multiple representations of the image. Since we said "allowsEditing = true" we need to set this to ".editedImage".
        guard let selectedImage = info[.editedImage] as? UIImage else {
    fatalError("“Expected a dictionary containing an image, but was provided the following: \(info)")
    }
    // Set photoImageView to display the selected image.
    self.imagePickedBlock?(selectedImage)
    // Dismiss the picker.
    currentVC.dismiss(animated: true, completion: nil)
    }
}

使用方法

  1. 确保您的信息PList设置如下图所示。 enter image description here

  2. 创建一个带有UIImageView的故事板,并将imageView拖动到ViewController中。这将创建一个类似于下面代码中看到的@IBOutlet。我将我的imageView命名为profileImageView。

  3. 创建一个UIImage并将其设置为资产文件夹中的图像或使用系统图像。如果使用系统图像,它应该像这样UIImage(systemName: "plus") 注意:plus是一个示例,可以在那里传递任何系统图像。

(4) 创建一个函数来更新profileImageView以满足您的需求,将图像添加到profileImageView,然后在ViewDidLoad()中调用此函数。

(5) 在同一函数中,我设置了一个tapGestureRecognizer,因此每次点击imageView时都会通知它并触发editImageTapGesture()函数。

(6) 设置editImageTapGesture函数以访问CameraHandler并显示操作表,以及将图像(您从库中选择或从相机中获取)分配给您的profileImageView。

import UIKit

class EditProfileImageController: UIViewController {


// (2) IBOutlet from storyboard

    @IBOutlet weak var profileImageView: UIImageView!
    
// (3) Add image: this can be a system image or in my case an image in my assets folder named "noImage".
    var profileImage = UIImage(named: "noImage")
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupProfileImage()
    }
    
//(4) I setup the profile image in this function and set profile image to the profileImageView 
    private func setupProfileImage() {
        profileImageView.contentMode = .scaleAspectFill
        profileImageView.image = profileImage

        //(5) setup tap gesture for when profileImageView is tapped
        profileImageView.isUserInteractionEnabled = true
        let editImageTapGesture = UITapGestureRecognizer(target: self, action: #selector(editProfileImageTapped(_:)))
        profileImageView.addGestureRecognizer(editImageTapGesture)
    }
    
    
   //(6) Once tap on profile image occurs the action sheet appears with Gallery and Camera buttons. 
    @objc func editProfileImageTapped(_ sender: UITapGestureRecognizer) {
        CameraHandler.shared.showActionSheet(vc: self)
        CameraHandler.shared.imagePickedBlock = { (image) in
            self.profileImageView.image = image 
        }
    }
}

动作表应该长这样: 在此输入图像描述


0

Swift 5: 你可以使用下方的相机图像: 在此输入图像描述

  1. 创建一个项目

  2. 在主Storyboard中,在底部添加两个按钮并添加imageView,然后链接到viewController。

  3. Info.plist中添加Privacy - Camera Usage Description权限,如下所示: enter image description here

  4. 将以下代码粘贴到视图控制器中:

    class ViewController: UIViewController {
    
       @IBOutlet weak var imageView: UIImageView!
    
       override func viewDidLoad() {
          super.viewDidLoad()       
        }
    
     @IBAction func btnPhotGalary(_ sender: Any) {
        let picker = UIImagePickerController()
        picker.sourceType = .photoLibrary
        picker.delegate = self
        present(picker, animated: true)
      }
    
    @IBAction func btnCapture(_ sender: Any) {
      let picker = UIImagePickerController()
      picker.sourceType = .camera
      //for camera front
      // picker.cameraDevice = .front
       picker.delegate = self
       picker.allowsEditing = false
       present(picker, animated: true)
      }
      }
    
      extension ViewController :UIImagePickerControllerDelegate,UINavigationControllerDelegate{
    
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        picker.dismiss(animated: true, completion: nil)
      }
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        picker.dismiss(animated: true, completion: nil)
        guard let originalImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage else {
         return
       }
        //for image rotation
        let image =  originalImage.upOrientationImage()
        imageView.image = image
      }
    
    }
    
     extension UIImage {
        func upOrientationImage() -> UIImage? {
         switch imageOrientation {
            case .up:
             return self
         default:
           UIGraphicsBeginImageContextWithOptions(size, false, scale)
            draw(in: CGRect(origin: .zero, size: size))
            let result = UIGraphicsGetImageFromCurrentImageContext()
              UIGraphicsEndImageContext()
            return result
           }
         }
     }
    
  1. 完整的源代码已经在GitHub上提供:https://github.com/enamul95/UIImagePicker.git

0

Swift 5 简单易行,只需调用函数

//MARK Life Cycles
override func viewDidLoad() {
    super.viewDidLoad()
    choosePicture
}



extension AddBook: UIPickerViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

@objc func choosePicture(){
    let alert  = UIAlertController(title: "Select Image", message: "", preferredStyle: .actionSheet)
    alert.modalPresentationStyle = .overCurrentContext
    alert.addAction(UIAlertAction(title: "Camera", style: .default, handler: { (action) in
        self.openCamera()
    }))
    alert.addAction(UIAlertAction(title: "Photo Library", style: .default, handler: { (action) in
        self.openGallary()
    }))
    
    alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
    
    let popoverController = alert.popoverPresentationController
    
    popoverController?.permittedArrowDirections = .up
    
    
    self.present(alert, animated: true, completion: nil)
}

func openCamera() {
    if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerController.SourceType.camera))
    {
        imagePicker.sourceType = UIImagePickerController.SourceType.camera
        imagePicker.allowsEditing = true
        self.present(imagePicker, animated: true, completion: nil)
    }
    else
    {
        let alert  = UIAlertController(title: "Warning", message: "You don't have camera", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
        self.present(alert, animated: true, completion: nil)
    }
}

func openGallary() {
    imagePicker.sourceType = UIImagePickerController.SourceType.photoLibrary
    imagePicker.allowsEditing = true
    self.present(imagePicker, animated: true, completion: nil)
}



func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
    picker.dismiss(animated: true, completion: nil)
}


private func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    // picker.supportedInterfaceOrientations = .
    if let image  = info[UIImagePickerController.InfoKey.originalImage.rawValue] as? UIImage {
        
            if btnPicOther.tag == 1 {
                btnPicOther.setImage(image, for: .normal)
            }
            else if btnPicBack.tag == 1 {
                btnPicBack.setImage(image, for: .normal)
            }
            else if btnPicFront.tag == 1{
                btnPicFront.setImage(image, for: .normal)
            }
            picker.dismiss(animated: true, completion: nil)
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接