Skip to content

开始使用

qingmei2 edited this page Jun 9, 2018 · 30 revisions

1.快速实现

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

sample_struct

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

1.1 打开系统相机和相册

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

public interface SystemImagePicker {

    @Gallery  //打开相册
    Observable<Result> openGallery();	

    @Camera   //打开相机
    Observable<Result> openCamera();
}

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

 SystemImagePicker imagePicker = new RxImagePicker.Builder()
                .with(this)
                .build()
                .create(SystemImagePicker.class);

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

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

imagePicker.openGallery()               //打开系统相册选取图片   
                .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 {

    String KEY_WECHAT_PICKER_ACTIVITY = "key_wechat_picker";

    @Gallery(viewKey = KEY_WECHAT_PICKER_ACTIVITY)
    Observable<Result> openGallery();

    @Camera
    Observable<Result> openCamera();
}

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

    WechatImagePicker imagePicker = new RxImagePicker.Builder()
                .with(this)
                .addCustomGallery(
                        WechatImagePicker.KEY_WECHAT_PICKER_ACTIVITY,
                        WechatImagePickerActivity.class,
                        new WechatConfigrationBuilder(MimeType.ofImage(), false)
                                .maxSelectable(9)	//最大可选图片数
                                .spanCount(4)		//每行展示四张图片
                                .countable(false)	//关闭计数模式
                                .theme(R.style.Wechat)	//微信主题
                                .build()
                )
                .build()
                .create(WechatImagePicker.class);

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

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

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

1.3 使用知乎主题UI

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

public interface ZhihuImagePicker {

    String KEY_ZHIHU_PICKER_NORMAL = "key_zhihu_picker_theme_normal";
    String KEY_ZHIHU_PICKER_DRACULA = "key_zhihu_picker_theme_dracula";

    @Gallery(viewKey = KEY_ZHIHU_PICKER_NORMAL)		//日间主题
    Observable<Result> openGalleryAsNormal();

    @Gallery(viewKey = KEY_ZHIHU_PICKER_DRACULA)	//夜间主题
    Observable<Result> openGalleryAsDracula();

    @Camera    //打开相机
    Observable<Result> openCamera();
}

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

ZhihuImagePicker imagePicker = new RxImagePicker.Builder()
                .with(this)
                .addCustomGallery(		//注入日间模式主题的UI
                        ZhihuImagePicker.KEY_ZHIHU_PICKER_NORMAL,
                        ZhihuImagePickerActivity.class,
                        new ZhihuConfigurationBuilder(MimeType.ofImage(), false)
                                .maxSelectable(9)	//最大可选择数量
                                .countable(true)	//可计数
                                .spanCount(4)		//每行图片数量
                                .theme(R.style.Zhihu_Normal)	//日间主题
                                .build()
                )
                .addCustomGallery(		//注入夜间模式主题的UI
                        ZhihuImagePicker.KEY_ZHIHU_PICKER_DRACULA,
                        ZhihuImagePickerActivity.class,
                        new ZhihuConfigurationBuilder(MimeType.ofImage(), false)
                                .spanCount(3)	  //每行图片数量
                                .maxSelectable(1) //最大可选择数量
                                .theme(R.style.Zhihu_Dracula)	//夜间主题
                                .build()
                )
                .build()
                .create(ZhihuImagePicker.class);

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

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

//打开日间主题相册选取图片,或者调用imagePicker.openGalleryAsDracula()打开夜间主题
imagePicker.openGalleryAsNormal()   
                .subscribe(new Consumer<result>() {
                    @Override
                    public void accept(Result result) throws Exception {
                        // 做您想做的,比如将选取的图片展示在ImageView中
                        GlideApp.with(this)
                                .load(result.getUri())
                                .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 将声明该注解所注释的方法 打开相册选择图片

它有两个参数:

  • viewKey 通过唯一的标识,映射要展示的UI

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

    并非所有的App的图片选择界面UI都是唯一的,比如,它可能有 夜间模式白天模式的两种UI。
    viewKey将会为该方法打上一个唯一的标识,同时,在初始化RxImagePicker时,对应的Activity.class或者Fragment实例都会被打上同样的标识,这样一对一的关系,保证了RxImagePicker对UI的正确展示:

public interface ZhihuImagePicker {

    String KEY_ZHIHU_PICKER_NORMAL = "key_zhihu_picker_theme_normal";
    String KEY_ZHIHU_PICKER_DRACULA = "key_zhihu_picker_theme_dracula";

    @Gallery(viewKey = KEY_ZHIHU_PICKER_NORMAL)
    Observable<Result> openGalleryAsNormal();

    @Gallery(viewKey = KEY_ZHIHU_PICKER_DRACULA)
    Observable<Result> openGalleryAsDracula();
}

请注意,如果没有使用viewKey标记,RxImagePicker会 默认打开系统的相册 选择图片。

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

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

2.1.2 @Camera

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

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

@Camera也提供了viewKey和containerViewId的接口,这是基于拓展性添加的接口,目前,配置它们没有任何意义。

2.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.3 ICustomPickerView接口

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

public interface ICustomPickerView {

    void display(FragmentActivity fragmentActivity,
                 @IdRes int viewContainer,
                 String viewKey,
                 ICustomPickerConfiguration configuration);

    Observable<Result> pickImage();

}

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

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

2.4 ICustomPickerConfiguration接口

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

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 返回:

这意味着,在选择的结果处理上,可以直接通过 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将直接 压缩好的图片的Uri 交给您,这需要额外的库或者代码处理。

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时,拓展库选择视频文件,会导致发生崩溃。