前言
如果想让你的App具有拍照与摄像的功能,如果你的App不是专门的拍照软件如美颜相机软件等,那么你不需要做很多操作,iOS内置的SDK已经帮我们准备好了界面和服务,我们只需要直接调用就可以了。 一个需要处理传照片的App,照片的来源共有三个。
- 相机
- 照片图库(Photo Library)
- 相簿(Photos Album)
相机一般用于即时拍摄并选择这张照片;照片图库会先呈现照片目录给使用者进行选择, 再从选择的目录中选择你需要的照片;相簿直接从Camera Roll这个相簿中选择照片,里面存放设备内所有的照片。
检查设备是否具有拍照功能
不同的iOS设备的相机或闪光灯的位置可能不同,例如可能只有后镜头而没有前镜头,或者根本没有拍照功能。UIImagePickerController为我们提供了检查的方法。
override func viewDidLoad() {
super.viewDidLoad()
if UIImagePickerController.isSourceTypeAvaliable(.camera) {
print("本设备具有拍照功能")
if UIImagePickerViewController.isCameraDeviceAvaliable(.front) {
print("有前方镜头")
}
if UIImagePickerViewController.isCameraDeviceAvaliable(.rear) {
print("有后方镜头")
}
if UIImagePickerViewController.isFlashAvaliable(.rear) {
print("有前方闪光灯")
}
if UIImagePickerViewController.isFlashAvaliable(.rear) {
print("有后方闪光灯")
}
}
}
拍照与存储
UIImagePickerController提供了系统的拍照与管理功能。 让App有三种不同的来源获取照片:
- .camera 代表开启相机让使用者拍照
- .photoLibrary 代表照片来自已经存储的照片
- .savedPhotosAlbum 代表照片来自某个特定的相簿,一般时Camera Roll
接下来介绍如何通过UIImagePickerController完成拍照功能。
- 首先需要在App的info.plist中新增[Privacy - Camera Usage Description] 键值询问使用者是否同意授权App使用相机。以及[Privacy - Photo Library Additions Usage Description]询问使用者是否同意授权App存储照片。
- 需要完成拍照功能的viewController需要遵循UINavigationController 和 UIImagePickerControlllerDelegate两个协议。
class ViewController: UIViewController, UINavigationController, UIImagePickerControllerDelegate {
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard UIImagePickerController.isSourceTypeAvailable(.camera) else {
print("设备没有相机")
return
}
let imagePicker = UIImagePickerController()
imagePicker.sourceType = .camera
iamgePicker.delegate = self
show(imagePicker, sender: self)
}
- 开启相机后,使用者可以选择拍照或者取消,如果使用者拍摄了一张照片,imagePickerController(_:didFinshPickingMediaWithInfo:)函数会被调用
func imagePickerController(_ picker: UIImagePickerController, didFinshPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
let image = info[.originalImage] as! UIImage
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
dismiss(animated: true, completion: nil)
}
选择一张照片
在之前,如果要在iPad上开启照片选择器,Apple强制要求必须以popover小视窗的方式。但现在UIPopoverPresentationController不管当前设备是iPhone还是iPad都会开启popover模式并自调整成适合的样式。
@IBAction func onClick(_ sender: UIButton) {
let imagePickerVC = UIImagePickerController()
imagePickerVC.sourceType = .photoLibrary
imagePickerVC.delegate = self
imagePickerVC.modalPresentationStyle = .popover
let popover = imagePickerVC.popoverPresentationController
popover?.sourceView = sender
popover?.sourceRect = sender.bounds
popover?.permittedArrowDirections = self
show(imagePickerVC, sender: self)
}
播放App内置的音乐
内置的音乐并不存储在设备中,如果删除App那么音乐也随App被删除了。 例:在一个ViewController中处理音乐的播放
import MediaPlayer
- 然后创建一个AVAudioPlayer类型的变量来处理音乐播放,再创建一个slider滑块显示与控制播放进度。
var audio: AVAudioPlayer?
- 在viewDidLoad()函数中设置AVAudioSession,目的是注册一个回调函数,让音乐播放过程中有状态改变时(如有电话导致音乐中断),可以通过这个回调函数处理音乐的中断与恢复播放。
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(audioInterrupted(_:)),
name: AVAudioSession.iterruptionNotification,
object: nil
)
do {
let url = Bundle.main.url(forResource: "music", withExtension: "mp3")
try AVAudioPlayer(coutentsOf: url!)
if audio != nil {
if audio!.prepareToPlay() {
print("开始播放音乐")
audio!.play()
slider.munimumValue = 0
slider.maximumValue = Float(audio!.duration)
slider.value = 0
Timer.scheduleTimer(withTimeInterval: 1.0, repeats: true) {
(timer) in
self.ticker(timer: timer)
}
}
}
} catch {
print(error)
}
}
- 实现audioInterrupted(_:)函数,通过传进来的参数notifaction来判断音乐中断或者是中断结束。
@objc func audioInterrupted(_ notification: NSNotification) {
gurad audio != nil, let userInfo = notification.userInfo else {
return
}
let type_tmp = userInfo[AVAudioSessiionInterruptionTypeKey] as! NSNumber
let type = AVAudioSession.InterruptionType(rawValue: type_tmp.uintValue)
switch type! {
case .began:
print("音乐中断")
case .ended:
print("音乐中断结束")
let option_tmp = userInfo[AVAudioSessionInterruptionOptionKey] as! NSNumber
let option = AVAudioSession.InterruptionOptions(rawValue: option_tmp.uintValue)
if option == .shouldResume && audio!.prepareToPlay() {
audio!.play()
}
@unknown default:
break
}
}
- 实现ticker(timer:)函数,每秒钟执行一次,更新slider的值,让进度值和播放进度一致。
func ticker(timer: timer) {
slider.value = Float(audio!.currentTime)
if !audio!.isPlaying {
print("音乐结束")
timer.invalidate()
}
}
- 实现sliderValueChanged(_:)函数,让使用者可以通过滑块控制音乐的播放进度
@IBAction func sliderValueChanged(_ sender: Any) {
audio?.currentTime = Double(slider.value)
}
|