-
Notifications
You must be signed in to change notification settings - Fork 155
开始使用
本章节内容旨在使开发者在 5分钟内快速实现 图片选择的需求,如果想获取更详细的代码,请参考sample中的实例代码:
请注意,请先阅读 开发准备 ,确认配置好 依赖 和 权限配置后,即可进行开发。
在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);
}
});
声明一个接口,并进行基础的配置
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);
}
});
声明一个接口,并进行基础的配置
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)
}
对于自定义UI的图片选择器,需要开发者根据实际需求进行编码,详情请参考这里
RxImagePicker最终的目的是在任何一个 Activity 或者 Fragment 中展示任何样式的图片选择UI。
这意味着,RxImagePicker不仅要提供接口,供开发者打开一个 完整的图片选择器界面 的Activity,同时,如果有需求,它也应该可以让开发者在Activity 任意大小的ViewGroup容器中 展示一个图片选择器,比如类似下图中QQ的设计:
对于自定义的UI,RxImagePicker提供了两种模式供开发者选择使用:
- 传一个Activity的class对象,和市面上众多的图片选择需求一样,结果是RxImagePicker会打开对应的Activity,用户选择图片后关闭该Activity,并进行下一步操作。
- 传一个Fragment对象,这意味着,RxImagePicker会将这个Fragment展示在Activity中的某个ViewGroup中并展示,就像上面的QQ界面一样,当然,您需要将对应的ViewGroup的id 通过 注解的方式 告知RxImagePicker,这个在 行为注解 一节中会讲到。
在这一小节中,我简单阐述了设计RxImagePicker过程中的一些思想,我认为这是有必要的,它可能会对您接下来使用 API时更加游刃有余。
RxImagePicker提供了2个行为注解,分别为@Gallery和@Camera。
@Gallery 将声明该注解所注释的方法 打开相册选择图片
@Camera 将声明该注解所注释的方法 打开相机拍照
请注意,接口的每个方法都 必须添加 行为注解以声明对应的行为,若方法未配置@Gallery或@Camera,RxImagePicker会在运行时抛出异常。
@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进行正确的展示。
@Camera 将声明该注解所注释的方法 打开相机拍照
请注意,目前@Camera只提供了调用 系统相机 进行拍照的功能。
@Camera也提供了
componentClazz: KClass<*>
,openAsFragment: Boolean
和containerViewId: Int
的接口,这是基于拓展性添加的接口,目前,配置它们没有任何意义。
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。
ImagePicker的每个接口方法都必须配置一个Context对象作为参数, 如果接口的方法没有任何参数,将会抛出NullPointerException
:
${method.name} requires just one instance of type: Context, but none.
这是无可厚非的,启动一个图片选择器的UI组件,必须依赖上下文对象。
【注意】这个Context必须是一个FragmentActivity,而不能是Application或其他,否则会抛出IllegalArgumentException
异常!
ICustomPickerConfiguration接口,作为标记,当类实现了该接口,RxImagePicker会将其视为自定义UI选择器对应的配置类。
对于打开系统相册或者系统相机而言,它没有配置的意义,但对于自定义的UI组件(比如Wechat主题和知乎主题),它是必须配置的。
RxImagePicker的基础组件并未提供实现类,如有疑问,请参考support包下的 SelectionSpec 类。
即使RxImagePicker提供了 微信图片选择器 和 知乎图片选择器 的UI样式,但是2套模板依然 不足以覆盖更多更精细的APP的UI需求 。
RxImagePicker提供了 足够自由度的接口 供开发者 私有化定制UI, 无论是一个新建一个Activity,或者是在当前的一个ViewGroup容器中展示,它都足以胜任 —— RxImagePicker_Support包提供了基础的UI组件,它很强大,上述的 微信图片选择器 和 知乎图片选择器 都是基于它进行的开发。
如果UI需求与 微信图片选择器 或者 知乎图片选择器 相似,建议您只添加RxImagePicker_Support包的依赖,并将对应主题模板的源码拉下来,简单修改代码调整UI即可 —— 如下所示,它们并不多:
如果涉及更复杂,则建议您视实际需求而定,是基于RxImagePicker_Support包自己写UI,亦或是自己动手—— 您只需要负责处理UI层的设计和代码编写,业务层交给RxImagePicker就好了。
该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会执行 自动压缩图片 的 拓展行为,这需要额外的图片处理库或者代码处理。
自版本号 0.3.0 之后,该注解已 废弃 并 删除,升级时请注意 不兼容性!
RxImagePicker提供了@AsFile/@AsBitmap/@AsUri三种数据类型注解 声明数据返回的格式:
@AsFile 返回File类型的数据
@AsBitmap 返回Bitmap类型的数据
@AsUri 返回Uri类型的数据
请注意,若方法未配置该类型的注解以声明数据应当返回的格式,则 默认以Uri的格式 进行数据的返回。
废弃原因: @AsBitmap和@AsFile可能会导致OOM异常的发生,同时,当设定为@AsBitmap时,拓展库选择视频文件,会导致发生崩溃。
开发者通过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的相关配置,都作为参数在方法调用时进行处理,进一步优化内存。
- 主页
- 2.x更新日志(RxJava2)
- 3.x更新日志(RxJava3 + AndroidX)
- 常见问题
- 开发准备
-
开始使用
- 1 快速实现
- 2 进阶使用
- 设计思想
- 2.1 行为注解
- 2.2 ICustomPickerView接口
- 2.3 【必要参数】Context
- 2.4 【可选参数】ICustomPickerConfiguration
- 2.5 实现完全自定义UI
- 2.6 选择结果Result和扩展数据
- 3 已废弃API