Skip to content

开始使用

qingmei2 edited this page Apr 17, 2019 · 30 revisions

1.快速实现

本章节内容旨在使开发者在 5分钟内快速实现 图片选择的需求,如果想获取更详细的代码,请参考sample中的实例代码:

sample_struct

请注意,请先阅读 开发准备 ,确认配置好 依赖权限配置后,即可进行开发。

1.1 打开系统相机和相册

在Activity的onCreate()方法中实例化SystemImagePicker:

 SystemImagePicker imagePicker = RxImagePicker.create();

在需要的地方使用SystemImagePicker打开相册或相机:

比如在Button的点击监听回调方法中添加如下代码:

     imagePicker.openGallery(this)               //打开系统相册选取图片   
                .subscribe(new Consumer<Result>() {
                    @Override
                    public void accept(Result result) throws Exception {
                        // 做您想做的,比如将选取的图片展示在ImageView中
                        GlideApp.with(this)
                                .load(result.getUri())
                                .into(imageView);
                    }
                });

1.2 使用微信主题UI

声明一个接口,并进行基础的配置

public interface WechatImagePicker {

    @Gallery(componentClazz = WechatImagePickerActivity.class,
            openAsFragment = false)
    Observable<Result> openGallery(Context context, ICustomPickerConfiguration config);

    @Camera
    Observable<Result> openCamera(Context context);
}

在Activity的onCreate()方法中实例化WechatImagePicker:

    WechatImagePicker imagePicker = RxImagePicker.create(WechatImagePicker.class);

在需要的地方使用WechatImagePicker打开相册或相机:

比如在Button的点击监听回调方法中添加如下代码:

imagePicker.openGallery(this,
                new WechatConfigrationBuilder(MimeType.INSTANCE.ofImage(), false)
                        .maxSelectable(9)
                        .countable(true)
                        .spanCount(4)
                        .countable(false)
                        .build())             //打开微信相册选取图片   
                .subscribe(new Consumer<Result>() {
                    @Override
                    public void accept(Result result) throws Exception {
                        // 做您想做的,比如将选取的图片展示在ImageView中
                        GlideApp.with(this)
                                .load(result.getUri())
                                .into(imageView);
                    }
                });

1.3 使用知乎主题UI(Kotlin版本,想要Java版本请参考上方微信主题的配置,依葫芦画瓢即可)

声明一个接口,并进行基础的配置

interface ZhihuImagePicker {

    @Gallery(componentClazz = ZhihuImagePickerActivity::class,
            openAsFragment = false)
    fun openGalleryAsNormal(context: Context,
                            config: ICustomPickerConfiguration): Observable<Result> //日间主题

    @Gallery(componentClazz = ZhihuImagePickerActivity::class,
            openAsFragment = false)
    fun openGalleryAsDracula(context: Context,
                             config: ICustomPickerConfiguration): Observable<Result> //夜间主题

    @Camera
    fun openCamera(context: Context): Observable<Result> //打开相机
}

在Activity的onCreate()方法中实例化ZhihuImagePicker:

ZhihuImagePicker rxImagePicker = RxImagePicker
                .create(ZhihuImagePicker::class.java)

在需要的地方使用ZhihuImagePicker打开相册或相机:

比如在Button的点击监听回调方法中添加如下代码:

//打开日间主题相册选取图片
  rxImagePicker.openGalleryAsNormal(this,
                ZhihuConfigurationBuilder(MimeType.ofImage(), false)
                        .maxSelectable(9)
                        .countable(true)
                        .spanCount(4)
                        .theme(R.style.Zhihu_Normal)
                        .build())
               .subscribe {
                    Glide.with(this@ZhihuActivity)
                            .load(it.uri)
                            .into(imageView)
                }

1.4 自定义图片选择器

对于自定义UI的图片选择器,需要开发者根据实际需求进行编码,详情请参考这里

2.进阶使用

设计思想

RxImagePicker最终的目的是在任何一个 Activity 或者 Fragment 中展示任何样式的图片选择UI。

这意味着,RxImagePicker不仅要提供接口,供开发者打开一个 完整的图片选择器界面 的Activity,同时,如果有需求,它也应该可以让开发者在Activity 任意大小的ViewGroup容器中 展示一个图片选择器,比如类似下图中QQ的设计:

screenshot_qq

对于自定义的UI,RxImagePicker提供了两种模式供开发者选择使用:

  • 传一个Activity的class对象,和市面上众多的图片选择需求一样,结果是RxImagePicker会打开对应的Activity,用户选择图片后关闭该Activity,并进行下一步操作。
  • 传一个Fragment对象,这意味着,RxImagePicker会将这个Fragment展示在Activity中的某个ViewGroup中并展示,就像上面的QQ界面一样,当然,您需要将对应的ViewGroup的id 通过 注解的方式 告知RxImagePicker,这个在 行为注解 一节中会讲到。

在这一小节中,我简单阐述了设计RxImagePicker过程中的一些思想,我认为这是有必要的,它可能会对您接下来使用 API时更加游刃有余。

2.1 行为注解

RxImagePicker提供了2个行为注解,分别为@Gallery和@Camera。

@Gallery 将声明该注解所注释的方法 打开相册选择图片
@Camera 将声明该注解所注释的方法 打开相机拍照

请注意,接口的每个方法都 必须添加 行为注解以声明对应的行为,若方法未配置@Gallery或@Camera,RxImagePicker会在运行时抛出异常。

2.1.1 @Gallery

@Gallery 将声明该注解所注释的方法 打开相册选择图片

它有3个参数:

  • componentClazz:KClass<*> UI组件的class对象,默认是打开系统相机的SystemGalleryPickerView::class

  • openAsFragment:Boolean 该UI组件是否作为Fragment展示在Activity的部分片段中,默认为true

  • containerViewId: Int 如果该UI需要作为Fragment展示在某个ViewGroup中,需要将ViewGroup对应的id赋值给它

    UI组件目前只支持两种:FragmentActivity或者是support-v4包下的Fragment。

    以打开系统相机为例,它的原理是,向当前的Activity中实例化一个不可见的Fragment,该Fragment通过Intent打开系统相册,并通过onActivityResult()方法处理回传的数据,因此它的实现方式为这样:

interface SystemImagePicker {

    @Gallery   //默认componentClazz:KClass = SystemGalleryPickerView::class,openAsFragment:Boolean=true
    fun openGallery(context: Context): Observable<Result>
}

当我需要自定义UI时,以Zhihu主题为例,我们就要将ZhihuImagePickerActivity::class配置给componentClazz,并将openAsFragment赋值为false:

interface ZhihuImagePicker {

    @Gallery(componentClazz = ZhihuImagePickerActivity::class,
            openAsFragment = false)
    fun openGalleryAsNormal(context: Context,
                            config: ICustomPickerConfiguration): Observable<Result>

    @Gallery(componentClazz = ZhihuImagePickerActivity::class,
            openAsFragment = false)
    fun openGalleryAsDracula(context: Context,
                             config: ICustomPickerConfiguration): Observable<Result>

    @Camera
    fun openCamera(context: Context): Observable<Result>
}

若想了解更多,请参考sample中的 ZhihuActivity

同时,如上文中设计思想所说的,当UI需要作为Fragment进行展示时,RxImagePicker需要被告知要展示的ViewGroup控件对应的id,因此需要将id交给containerViewId,以供RxImagePicker进行正确的展示。

2.1.2 @Camera

@Camera 将声明该注解所注释的方法 打开相机拍照

请注意,目前@Camera只提供了调用 系统相机 进行拍照的功能。

@Camera也提供了componentClazz: KClass<*>,openAsFragment: BooleancontainerViewId: Int的接口,这是基于拓展性添加的接口,目前,配置它们没有任何意义。

2.2 ICustomPickerView接口

ICustomPickerView是一个底层的接口,用于控制 展示图片选择器界面 以及 获取用户选择结果,它本身暴露出了两个方法:

interface ICustomPickerView {

    fun display(fragmentActivity: FragmentActivity,
                @IdRes viewContainer: Int,
                configuration: ICustomPickerConfiguration?)

    fun pickImage(): Observable<Result>
}

它有几个经典的实现类,当通过配置打开对应的图片选择器Activity时,ICustomPickerView为ImagePickerDisplayer;

当通过配置Fragment,并将其放入当前Activity中并展示,对应的Fragment需要实现ICustomPickerView接口,请参考sample中的ZhihuImagePickerFragment或者WechatImagePickerFragment

2.3 【必要参数】Context

ImagePicker的每个接口方法都必须配置一个Context对象作为参数, 如果接口的方法没有任何参数,将会抛出NullPointerException:

${method.name} requires just one instance of type: Context, but none.

这是无可厚非的,启动一个图片选择器的UI组件,必须依赖上下文对象。

【注意】这个Context必须是一个FragmentActivity,而不能是Application或其他,否则会抛出IllegalArgumentException异常!

2.4 【可选参数】ICustomPickerConfiguration

ICustomPickerConfiguration接口,作为标记,当类实现了该接口,RxImagePicker会将其视为自定义UI选择器对应的配置类。

对于打开系统相册或者系统相机而言,它没有配置的意义,但对于自定义的UI组件(比如Wechat主题知乎主题),它是必须配置的。

RxImagePicker的基础组件并未提供实现类,如有疑问,请参考support包下的 SelectionSpec 类。

2.5 实现完全自定义UI

即使RxImagePicker提供了 微信图片选择器知乎图片选择器 的UI样式,但是2套模板依然 不足以覆盖更多更精细的APP的UI需求

RxImagePicker提供了 足够自由度的接口 供开发者 私有化定制UI, 无论是一个新建一个Activity,或者是在当前的一个ViewGroup容器中展示,它都足以胜任 —— RxImagePicker_Support包提供了基础的UI组件,它很强大,上述的 微信图片选择器知乎图片选择器 都是基于它进行的开发。

如果UI需求与 微信图片选择器 或者 知乎图片选择器 相似,建议您只添加RxImagePicker_Support包的依赖,并将对应主题模板的源码拉下来,简单修改代码调整UI即可 —— 如下所示,它们并不多:

wechat_struct zhihu_struct

如果涉及更复杂,则建议您视实际需求而定,是基于RxImagePicker_Support包自己写UI,亦或是自己动手—— 您只需要负责处理UI层的设计和代码编写,业务层交给RxImagePicker就好了。

2.6 选择结果Result和ExtraData

该API特性仅在 v0.4.0 之后的版本提供支持。

图片选择的需求,不可避免会有额外的 扩展数据 要求返回。举例来说,微信的图片选择器,就会有 发送原图 的选项。

RxImagePicker 在v0.4.0之后的版本,将选择结果的返回值,通过包装为 Result 返回:

screenshot_result_class

这意味着,在选择的结果处理上,可以直接通过 Result.getUri() 获取选择结果的Uri并进行展示等处理,如果有其它 拓展数据 的返回,则可以通过 Result.getXXXExtra() 获取它们—— 当然前提是,您需要 在对应的选择器界面将扩展数据配置给Result (对此,你可以 参考这里 来查看Wechat主题是如何配置它们的。)。

这之后,你就可以通过获取到的 扩展数据 进行对应的操作:

boolean originalMode = result.getBooleanExtra("EXTRA_ORIGINAL_IMAGE", false);
Log.d(TAG, "该图片是否要发送原图:" + originalMode + " , uri path: " + result.getUri().getPath());

请注意,扩展数据 仅仅是配置数据,并不代表RxImagePicker会执行 自动压缩图片拓展行为,这需要额外的图片处理库或者代码处理。

3.已废弃API

3.1 数据类型注解(After 0.3.0)

自版本号 0.3.0 之后,该注解已 废弃删除,升级时请注意 不兼容性

RxImagePicker提供了@AsFile/@AsBitmap/@AsUri三种数据类型注解 声明数据返回的格式

3.1.1 @AsFile

@AsFile 返回File类型的数据

3.1.2 @AsBitmap

@AsBitmap 返回Bitmap类型的数据

3.1.3 @AsUri

@AsUri 返回Uri类型的数据

请注意,若方法未配置该类型的注解以声明数据应当返回的格式,则 默认以Uri的格式 进行数据的返回。

废弃原因: @AsBitmap和@AsFile可能会导致OOM异常的发生,同时,当设定为@AsBitmap时,拓展库选择视频文件,会导致发生崩溃。

3.2 RxImagePicker.Builder

开发者通过Builder类,将必要的依赖进行注入,让RxImagePicker能够灵活调用并展示各种各样的UI。

以自定义的仿微信图片选择器为例,开发者需要做出如下配置:

rxImagePicker = new RxImagePicker.Builder()
                .with(this)                                            //注入Activity
                .addCustomGallery(
                        WechatImagePicker.KEY_WECHAT_PICKER_ACTIVITY,  //ViewKey
                        WechatImagePickerActivity.class,               //要打开哪个Activity
                        new WechatConfigrationBuilder(MimeType.ofImage(), false)  //微信图片选择器UI的配置
                                .maxSelectable(9)
                                .countable(true)
                                .spanCount(4)
                                .countable(false)
                                .theme(R.style.Wechat)
                                .build()
                )
                .build()
                .create(WechatImagePicker.class);

实际上代码中注入的依赖,都被暂时存储到了Builder对象中,以供RxImagePicker之后调用。

废弃原因: 自2.2.0版本之后,RxImagePicker进行了重构,无论是Context对象,还是UI的相关配置,都作为参数在方法调用时进行处理,进一步优化内存。