❸❶ iOS SDK View Controller & Delegate for Picking Up Selections

Janus
彼得潘的 Swift iOS / Flutter App 開發教室
8 min readJan 26, 2024

These are protocols for user selections.

UIImagePickerControllerDelegate & UINavigationControllerDelegate

For UIImagePickerControllerDelegate will show the library window popped up, for taking photos we need UINavigationControllerDelegate. It allows the view controller to respond to navigation-related events if needed, providing a more complete and adaptable implemention.

Privacy — Camera Usage Description

Set the message.

The take photo function can only run on actual simulation.

//  Created on 2024/1/16.

import UIKit
import AVKit

// ViewController class conforms to three protocols: UIViewController, UIImagePickerControllerDelegate, and UINavigationControllerDelegate
class ViewController: UIViewController & UIImagePickerControllerDelegate & UINavigationControllerDelegate {

// IBOutlet to connect with the UIImageView in the storyboard
@IBOutlet weak var imageView: UIImageView!

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}

// IBAction function triggered when the "Select Picture" button is pressed
@IBAction func SelectPixture(_ sender: UIButton) {
// Create an instance of UIImagePickerController
let controller = UIImagePickerController()

// Set the source type to photo library
controller.sourceType = .photoLibrary

// Set the delegate to self, so this view controller will handle image picker events
controller.delegate = self

// Present the image picker controller
present(controller, animated: true)
}

// Function called when the user picks an image from the photo library or camera
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

// Uncomment the following line for testing purposes
// print("selected")

// Extract the selected image from the dictionary
let image = info[.originalImage] as? UIImage

// Set the selected image to the UIImageView
imageView.image = image

// Dismiss the image picker controller
dismiss(animated: true)
}

// IBAction function triggered when the "Camera" button is pressed
@IBAction func pressedCamera(_ sender: Any) {
// Create an instance of UIImagePickerController
let controller = UIImagePickerController()

PHPickerViewControllerDelegate

For picking one or multiple photo selections.

Select Single Photo

Add 2 imageView 1 button.

When segue the imageView choose the Outlet Collection

class ViewController: UIViewController {
@IBOutlet var ImagesArea: [UIImageView]!

Segue Button Action

    @IBAction func pressedShot(_ sender: Any) {
}

Add FrameWork

import PhotosUI

Add delegate

class ViewController: UIViewController & PHPickerViewControllerDelegate {

Define the DidFinishPicking Function

extension ViewController: PHPickerViewControllerDelegate {
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true)

let itemProviders = results.map(\.itemProvider)
if let itemProvider = itemProviders.first, itemProvider.canLoadObject(ofClass: UIImage.self) {
let previousImage = self.imageViews.first?.image
itemProvider.loadObject(ofClass: UIImage.self) {[weak self] (image, error) in
DispatchQueue.main.async {
guard let self = self, let image = image as? UIImage, self.imageViews.first?.image == previousImage else { return }
self.imageViews.first?.image = image
}
}
}
}

}

Select Multiple Photo

Add another button and also set the IBAction.

Set selection limits

 @IBAction func MultiplePhotos(_ sender: UIButton) {

var configuration = PHPickerConfiguration()
configuration.filter = .images
configuration.selectionLimit = 2
let picker = PHPickerViewController(configuration: configuration)
picker.delegate = self
present(picker, animated: true)

}

Set Function

extension ViewController: PHPickerViewControllerDelegate {
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true)

let itemProviders = results.map(\.itemProvider)
for (i, itemProvider) in itemProviders.enumerated() where itemProvider.canLoadObject(ofClass: UIImage.self) {

let previousImage = self.imageViews[i].image
itemProvider.loadObject(ofClass: UIImage.self) {[weak self] (image, error) in
DispatchQueue.main.async {
guard let self = self, let image = image as? UIImage, self.imageViews[i].image == previousImage else { return }
self.imageViews[i].image = image
}
}

}

}

}

import UIKit
import PhotosUI

class ViewController: UIViewController & PHPickerViewControllerDelegate {

@IBOutlet var ImagesArea: [UIImageView]!

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}

@IBAction func pressedShot(_ sender: Any) {
var configuration = PHPickerConfiguration()
configuration.filter = .images
let picker = PHPickerViewController(configuration: configuration)
picker.delegate = self
present(picker, animated: true)
}

// this function for only 1 photo selection
// func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
// picker.dismiss(animated: true)
//
// let itemProviders = results.map(\.itemProvider)
// if let itemProvider = itemProviders.first, itemProvider.canLoadObject(ofClass: UIImage.self) {
// let previousImage = self.ImagesArea.first?.image
// itemProvider.loadObject(ofClass: UIImage.self) {[weak self] (image, error) in
// DispatchQueue.main.async {
// guard let self = self, let image = image as? UIImage, self.ImagesArea.first?.image == previousImage else { return }
// self.ImagesArea.first?.image = image
// }
// }
// }
// }

@IBAction func MultiplePhotos(_ sender: UIButton) {
var configuration = PHPickerConfiguration()
configuration.filter = .images
configuration.selectionLimit = 2
let picker = PHPickerViewController(configuration: configuration)
picker.delegate = self
present(picker, animated: true)

}


func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true)

let itemProviders = results.map(\.itemProvider)

for (i, itemProvider) in itemProviders.enumerated() where itemProvider.canLoadObject(ofClass: UIImage.self) {
let previousImage = self.ImagesArea[i].image
itemProvider.loadObject(ofClass: UIImage.self) { [weak self] (image, error) in
DispatchQueue.main.async {
guard let self = self, let image = image as? UIImage, self.ImagesArea[i].image == previousImage else { return }
self.ImagesArea[i].image = image
}
}
}
}
}

UIColorPickerViewController

Select Color Button

 @IBAction func selectColor(_ sender: UIButton) {  

let controller = UIColorPickerViewController()
controller.delegate = self
present(controller, animated: true)

}

Set the Background Color

func colorPickerViewController(_ viewController: UIColorPickerViewController, didSelect color: UIColor, continuously: Bool) {           
view.backgroundColor = color
}
(Remember add the delegate)

UIDocumentPickerViewController

import UniformTypeIdentifiers. 
(Remember add the delegate)

Add new button and IBAction + type shorter and quicker. Also segue an IBOulet for single photo display using.

Display the controller as UIDocumentPickerViewController.

When creating UIDocumentPickerViewController, the Parameter forOpeningContentTypes control the file type hence we assign in [.png, .jpg]. The parameter asCopy we assign true allow us storage the file in the app.

 @IBOutlet weak var imageView: UIImageView!

@IBAction func selectFile(_ sender: UIButton) {

let controller = UIDocumentPickerViewController(forOpeningContentTypes: [.png, .jpeg], asCopy: true)
controller.delegate = self
present(controller, animated: true)

}

documentPicker (_ controller: didPickDocumentsAT: )

Set the url for the path selecting photo, after select photo, set the IBOutlet imageView photo.

func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
if let url = urls.first,
let image = UIImage(contentsOfFile: url.path) {

imageView.image = image // reconnect the IBOutlet for 1 imageView

}
}

MPMediaPickerController

This can only test in iphone. Can load in Music App puchased music or Applse music if you are a subscriber.

Import MediaPlayer

import MediaPlayer

Add Delegate

+Privacy — Media Library Usage Description

  • Get the selected music and play.
 func mediaPicker(_ mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection) {
let musicPlayer = MPMusicPlayerController.systemMusicPlayer
musicPlayer.setQueue(with: mediaItemCollection)
musicPlayer.play()
mediaPicker.dismiss(animated: true)
}
}

UIFontPickerViewController

extension ViewController: UIFontPickerViewControllerDelegate {

}

Set a outlet Label & Action

 @IBOutlet weak var textLabel: UILabel!

@IBAction func selectFont(_ sender: Any) {
let fontConfig = UIFontPickerViewController.Configuration()
fontConfig.includeFaces = true
let fontPicker = UIFontPickerViewController(configuration: fontConfig)
fontPicker.delegate = self
present(fontPicker, animated: true)
}

Set Function for acquiring the Font of Outlet Label.

    func fontPickerViewControllerDidPickFont(_ viewController: UIFontPickerViewController) {
if let selectedFontDescriptor = viewController.selectedFontDescriptor {
textLabel.font = UIFont(descriptor: selectedFontDescriptor, size: textLabel.font.pointSize)
}
dismiss(animated: true)
}

CNContactPickerViewController

Based this protocol CNContactPickerDelegate, imoprt ContactsUI

import ContactsUI

extension ViewController: CNContactViewControllerDelegate{
}

Link the button into IBAction, show the CNContactPickerViewController.

  @IBAction func selectContact(_ sender: Any) {
let controller = CNContactViewController()
controller.delegate = self
present(controller, animated: true)
}

To Retrieve the name and number of the contact.

extension ViewController: CNContactPickerDelegate{

func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact)
textView.text = contact.givenName
if let phoneNumber = contact.phoneNumbers.first?.value {
textView.text.append(" \(phoneNumber.stringValue)")
}
}
}

UIVideoEditorController

import AVFoundation

extension ViewController: UIVideoEditorControllerDelegate, UINavigationControllerDelegate{

}

Show the UIVideoEditor on IBAction

Put video in the Navigator area.

Back to extension, videoEditorController(_:didSaveEditedVideoToPath:) to acquire the edited video and diaplay on screen.

 func videoEditorController(_ editor: UIVideoEditorController, didSaveEditedVideoToPath editedVideoPath: String) {
let player = AVPlayer(url: URL(filePath: editedVideoPath))


let playerLayer = AVPlayerLayer()
playerLayer.frame = CGRect(x: 50, y: 50, width: 200, height: 250)
playerLayer.videoGravity = .resizeAspectFill //videoDisplayMode
playerLayer.player = player //make player with this playLayer CONNECT
view.layer.addSublayer(playerLayer) //let the player on the view layer
player.play() //play the vid

dismiss(animated: true)
}

}

This controller can only be simulated on iPhone.


//
// ViewController.swift
// Practice_UIVideoEditorController
//
// Created by yucian huang on 2024/1/26.
//

import UIKit
import AVFoundation

class ViewController: UIViewController{

override func viewDidLoad() {
super.viewDidLoad()
}


@IBAction func editVideo(_ sender: Any) {
if let path = Bundle.main.path(forResource: "333", ofType: "mp4"),
UIVideoEditorController.canEditVideo(atPath: path) {
let controller = UIVideoEditorController()
controller.videoPath = path
controller.delegate = self
present(controller, animated: true)
}
}
}

extension ViewController: UIVideoEditorControllerDelegate, UINavigationControllerDelegate{

func videoEditorController(_ editor: UIVideoEditorController, didSaveEditedVideoToPath editedVideoPath: String) {
let player = AVPlayer(url: URL(filePath: editedVideoPath))


let playerLayer = AVPlayerLayer()
playerLayer.frame = CGRect(x: 50, y: 50, width: 200, height: 250)
playerLayer.videoGravity = .resizeAspectFill //videoDisplayMode
playerLayer.player = player //make player with this playLayer CONNECT
view.layer.addSublayer(playerLayer) //let the player on the view layer
player.play() //play the vid

dismiss(animated: true)
}
}

Reference:

--

--

Janus
彼得潘的 Swift iOS / Flutter App 開發教室

Sharing ideas and learning code progress. More like a diary space now, newbie diary.