ImagePicker - 图片选择器

ImagePicker - 图片选择器 - 图1

这是一个图片选择器的演示,你可以在这里下载这个例子


简介

这个 App 主要有这样几个交互:

  • 当用点击相机按钮时,让用户拍一张照片,然后显示出来。
  • 当用点击相册按钮时,让用户从相册中选出照片,然后显示出来。
  • 当用点击裁剪按钮时,让用户从相册中选出照片编辑,然后显示出来。

整体结构

ImagePicker - 图片选择器 - 图2

  1. ...
  2. override func viewDidLoad() {
  3. super.viewDidLoad()
  4. ...
  5. cameraButton.rx.tap
  6. .flatMapLatest { [weak self] _ in
  7. return UIImagePickerController.rx.createWithParent(self) { picker in
  8. picker.sourceType = .camera
  9. picker.allowsEditing = false
  10. }
  11. .flatMap { $0.rx.didFinishPickingMediaWithInfo }
  12. .take(1)
  13. }
  14. .map { info in
  15. return info[UIImagePickerControllerOriginalImage] as? UIImage
  16. }
  17. .bind(to: imageView.rx.image)
  18. .disposed(by: disposeBag)
  19. ...
  20. }

我们忽略一些细节,看一下序列的转换过程:

  1. cameraButton.rx.tap
  2. .flatMapLatest { () -> Observable<[String: AnyObject]> ... } // 点击 -> 图片信息
  3. .map { [String : AnyObject] -> UIImage? ... } // 图片信息 -> 图片
  4. .bind(to: imageView.rx.image) // 数据绑定
  5. .disposed(by: disposeBag)

最开始的按钮点击是一个 Void 序列,接着用 flatMapLatest 将它异步转化为图片信息序列 [String : AnyObject],然后用 map 同步的从图片信息中取出图片,从而得到了一个图片序列 UIImage?,最后将这个图片序列绑定到 imageView 上:

ImagePicker - 图片选择器 - 图3

这是相机按钮点击后需要执行的操作。另外两个按钮(相册和裁剪)和它十分相似,只不过传入了不同的参数,通过不同的键取出图片:

  1. ...
  2. override func viewDidLoad() {
  3. super.viewDidLoad()
  4. ...
  5. // 相机
  6. cameraButton.rx.tap
  7. .flatMapLatest { [weak self] _ in
  8. return UIImagePickerController.rx.createWithParent(self) { picker in
  9. picker.sourceType = .camera
  10. picker.allowsEditing = false
  11. }
  12. .flatMap { $0.rx.didFinishPickingMediaWithInfo }
  13. .take(1)
  14. }
  15. .map { info in
  16. return info[UIImagePickerControllerOriginalImage] as? UIImage
  17. }
  18. .bind(to: imageView.rx.image)
  19. .disposed(by: disposeBag)
  20. // 相册
  21. galleryButton.rx.tap
  22. .flatMapLatest { [weak self] _ in
  23. return UIImagePickerController.rx.createWithParent(self) { picker in
  24. picker.sourceType = .photoLibrary
  25. picker.allowsEditing = false
  26. }
  27. .flatMap {
  28. $0.rx.didFinishPickingMediaWithInfo
  29. }
  30. .take(1)
  31. }
  32. .map { info in
  33. return info[UIImagePickerControllerOriginalImage] as? UIImage
  34. }
  35. .bind(to: imageView.rx.image)
  36. .disposed(by: disposeBag)
  37. // 裁剪
  38. cropButton.rx.tap
  39. .flatMapLatest { [weak self] _ in
  40. return UIImagePickerController.rx.createWithParent(self) { picker in
  41. picker.sourceType = .photoLibrary
  42. picker.allowsEditing = true
  43. }
  44. .flatMap { $0.rx.didFinishPickingMediaWithInfo }
  45. .take(1)
  46. }
  47. .map { info in
  48. return info[UIImagePickerControllerEditedImage] as? UIImage
  49. }
  50. .bind(to: imageView.rx.image)
  51. .disposed(by: disposeBag)
  52. }
  53. ...

参考