# ImagePicker - 图片选择器

![](/files/-MWlwPPCoOn1ymp7WkVY)

这是一个图片选择器的演示，你可以在这里下载[这个例子](https://github.com/ReactiveX/RxSwift/tree/master/RxExample/RxExample/Examples/ImagePicker)。

## 简介

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

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

## 整体结构

![](/files/-MWlwPPDOQJhYNR-E363)

```swift
...
override func viewDidLoad() {
    super.viewDidLoad()

    ...

    cameraButton.rx.tap
        .flatMapLatest { [weak self] _ in
            return UIImagePickerController.rx.createWithParent(self) { picker in
                picker.sourceType = .camera
                picker.allowsEditing = false
            }
            .flatMap { $0.rx.didFinishPickingMediaWithInfo }
            .take(1)
        }
        .map { info in
            return info[.originalImage] as? UIImage
        }
        .bind(to: imageView.rx.image)
        .disposed(by: disposeBag)

    ...    
}
```

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

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

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

![](/files/-MWlwPPFlMjSzmix4sEb)

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

```swift
...
override func viewDidLoad() {
    super.viewDidLoad()

    ...

    // 相机
    cameraButton.rx.tap
        .flatMapLatest { [weak self] _ in
            return UIImagePickerController.rx.createWithParent(self) { picker in
                picker.sourceType = .camera
                picker.allowsEditing = false
            }
            .flatMap { $0.rx.didFinishPickingMediaWithInfo }
            .take(1)
        }
        .map { info in
            return info[UIImagePickerControllerOriginalImage] as? UIImage
        }
        .bind(to: imageView.rx.image)
        .disposed(by: disposeBag)

    // 相册
    galleryButton.rx.tap
        .flatMapLatest { [weak self] _ in
            return UIImagePickerController.rx.createWithParent(self) { picker in
                picker.sourceType = .photoLibrary
                picker.allowsEditing = false
            }
            .flatMap {
                $0.rx.didFinishPickingMediaWithInfo
            }
            .take(1)
        }
        .map { info in
            return info[.originalImage] as? UIImage
        }
        .bind(to: imageView.rx.image)
        .disposed(by: disposeBag)

    // 裁剪
    cropButton.rx.tap
        .flatMapLatest { [weak self] _ in
            return UIImagePickerController.rx.createWithParent(self) { picker in
                picker.sourceType = .photoLibrary
                picker.allowsEditing = true
            }
            .flatMap { $0.rx.didFinishPickingMediaWithInfo }
            .take(1)
        }
        .map { info in
            return info[.editedImage] as? UIImage
        }
        .bind(to: imageView.rx.image)
        .disposed(by: disposeBag)
}
...
```

## 参考

* [flatMap](/rxswift/decision_tree/flatmap.md)
* [flatMapLatest](/rxswift/decision_tree/flatmaplatest.md)
* [map](/rxswift/decision_tree/map.md)
* [take](/rxswift/decision_tree/take.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://3440217568.gitbook.io/rxswift/more_demo/image_picker.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
