Skip to content

Commit 7b34879

Browse files
authored
Update README.md
1 parent 3156a29 commit 7b34879

File tree

1 file changed

+230
-69
lines changed

1 file changed

+230
-69
lines changed

README.md

Lines changed: 230 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,252 @@
1-
# ImageExt 参考Coil对Glide封装实现
1+
# 参考Coil对Glide封装实现
2+
> 主要为ImageView添加扩展函数来简化常见图片加载api [![](https://jitpack.io/v/forJrking/ImageExt.svg)](https://jitpack.io/#forJrking/ImageExt)
23
3-
### 主要为ImageView添加扩展函数来简化常见图片加载api [![](https://jitpack.io/v/forJrking/ImageExt.svg)](https://jitpack.io/#forJrking/ImageExt)
4+
## 前言
45

5-
![img](img/img.gif)
6+
`glide``Google 官方`推荐的一款图片加载库,Coil是号称[Kotlin-first的Android图片加载库](https://juejin.cn/post/6844903913007611917) ,融合了kotlin特性、android最主流的技术和趋势,本篇我们主要分享如何用`kotlin``glide`封装的使用起来像`coil`一样。
67

7-
## 使用方法
8+
## 集成和API预览
89

9-
```groovy
10-
allprojects {
11-
repositories {
12-
...
13-
maven { url 'https://www.jitpack.io' }
14-
}
10+
1. ```groovy
11+
allprojects {
12+
repositories {
13+
maven { url 'https://www.jitpack.io' }
14+
}
15+
}
16+
```
17+
18+
2. ```groovy
19+
dependencies {
20+
implementation 'com.github.forJrking:ImageExt:0.0.2'
21+
}
22+
```
23+
24+
3. ```kotlin
25+
// URL
26+
imageView.load("https://www.example.com/image.jpg")
27+
// Resource
28+
imageView.load(R.drawable.image)
29+
//回调和进度监听
30+
imageView.load("https://www.example.com/image.jpg") {
31+
placeHolderResId = R.drawable.placeholder
32+
transformation = arrayOf(GrayscaleTransformation())
33+
progressListener { isComplete, percentage, bytesRead, totalBytes ->
34+
//加载进度
35+
}
36+
requestListener {
37+
onSuccess {
38+
}
39+
onFail {
40+
}
41+
}
42+
}
43+
```
44+
45+
4. 其他扩展函数和效果
46+
47+
```kotlin
48+
ImageView.loadImage(...)
49+
ImageView.loadProgressImage(...)
50+
ImageView.loadResizeImage(...)
51+
ImageView.loadGrayImage(...)
52+
ImageView.loadBlurImage(...)
53+
ImageView.loadBlurImage(...)
54+
ImageView.loadRoundCornerImage(...)
55+
ImageView.loadCircleImage(...)
56+
ImageView.loadBorderImage(...)
57+
```
58+
59+
![](https://files.catbox.moe/f27rwx.gif)
60+
61+
## 封装实现
62+
63+
首先看coil的调用方式采用了`kotlin`扩展函数形式,给ImageView增加了一个`load(url)`函数,然后其他占位图等配置通过DSL方式去设置。DSL如何学习和使用后面单独说。
64+
65+
第一步封装如下一个函数:
66+
67+
```kotlin
68+
/**模仿 coil DSL写法**/
69+
fun ImageView.load(load: Any?, options: (ImageOptions.() -> Unit)? = null) {
70+
ImageLoader.loadImage(ImageOptions(load).also(options))
1571
}
1672
```
1773

18-
```groovy
19-
dependencies {
20-
implementation 'com.github.forJrking:ImageExt:0.0.1'
74+
第二步封装配置类:
75+
76+
```kotlin
77+
/**
78+
* 图片加载库的配置,封装原始加载配置属性,进行转换
79+
*/
80+
class ImageOptions {
81+
/*** 加载原始资源*/
82+
var res: Any? = null
83+
/*** 显示容器*/
84+
var imageView: ImageView? = null
85+
/*** imageView存在的上下文或者fragment\activity*/
86+
var context: Any? = null
87+
get() {
88+
return field ?: imageView
89+
}
90+
/*** 加载占位图资源ID,如果placeholder是0表示没有占位图*/
91+
@DrawableRes
92+
var placeHolderResId = 0
93+
.... 省略其动画、错误图等等他属性
94+
var centerCrop: Boolean = false
95+
/*** 网络进度监听器*/
96+
var onProgressListener: OnProgressListener? = null
97+
/*** 加载监听*/
98+
var requestListener: OnImageListener? = null
99+
....省略缓存策略和优先级等等枚举
21100
}
22101
```
102+
103+
第三步 策略实现,由于要使用okhttp拦截器做进度监听,通过注解方式配置glide的网络下载器。
104+
23105
```kotlin
24-
iv_2.loadImage(url, placeHolder = R.color.blue)
25-
//模糊
26-
iv_3.loadBlurImage(url)
27-
//圆形
28-
iv_4.loadCircleImage(url)
29-
//边框
30-
iv_5.loadBorderImage(url, borderWidth = 10, borderColor = Color.RED)
31-
//黑白
32-
iv_6.loadGrayImage(url)
33-
//圆角
34-
iv_7.loadRoundCornerImage(url, radius = 10, type = ImageOptions.CornerType.ALL)
35-
//resize
36-
iv_8.loadResizeImage(url, width = 400, height = 800)
37-
//监听回调结果
38-
iv_9.loadImage(url4, requestListener = {
39-
onSuccess {
40-
Toast.makeText(application, R.string.load_success, Toast.LENGTH_LONG).show()
41-
}
42-
onFail {
43-
Toast.makeText(application, R.string.load_failed, Toast.LENGTH_SHORT).show()
44-
}
45-
})
46-
//终极扩展 参数非常多必须使用可选参数方式调用
47-
iv_8.load(url1) {
48-
placeHolderResId = R.color.black
49-
transformation = arrayOf(GrayscaleTransformation())
50-
progressListener { isComplete, percentage, bytesRead, totalBytes ->
51-
//加载进度
52-
}
53-
requestListener {
54-
onSuccess {
106+
/**Glide策略封装*/
107+
object ImageLoader {
108+
fun loadImage(options: ImageOptions) {
109+
Preconditions.checkNotNull(options, "ImageConfigImpl is required")
110+
val context = options.context
111+
Preconditions.checkNotNull(context, "Context is required")
112+
Preconditions.checkNotNull(options.imageView, "ImageView is required")
113+
val requestsWith = glideRequests(context)
114+
//根据类型获取
115+
val glideRequest = when (options.res) {
116+
is String -> requestsWith.load(options.res as String)
117+
is Bitmap -> requestsWith.load(options.res as Bitmap)
118+
is Drawable -> requestsWith.load(options.res as Drawable)
119+
is Uri -> requestsWith.load(options.res as Uri)
120+
is URL -> requestsWith.load(options.res as URL)
121+
is File -> requestsWith.load(options.res as File)
122+
is Int -> requestsWith.load(options.res as Int)
123+
is ByteArray -> requestsWith.load(options.res as ByteArray)
124+
else -> requestsWith.load(options.res)
125+
}
126+
127+
glideRequest.apply {
128+
// 占位图、错误图
129+
...
130+
//缓存配置,优先级,缩略图请求
131+
...
132+
//动画、transformation
133+
into(GlideImageViewTarget(options.imageView, options.res))
134+
}
135+
136+
options.onProgressListener?.let {
137+
ProgressManager.addListener(options.res.toString(), options.onProgressListener)
55138
}
56-
onFail {
139+
}
140+
private fun glideRequests(context: Any?): GlideRequests {
141+
return when (context) {
142+
is Context -> IGlideModule.with(context)
143+
is Activity -> IGlideModule.with(context)
144+
is FragmentActivity -> IGlideModule.with(context)
145+
is Fragment -> IGlideModule.with(context)
146+
is android.app.Fragment -> IGlideModule.with(context)
147+
is View -> IGlideModule.with(context)
148+
else -> throw NullPointerException("not support")
57149
}
58150
}
59151
}
60-
//超长扩展函数 选用建议用上面DSL方式
61-
iv_9.loadImage(load = R.drawable.test, with = MainActivity@ this,
62-
placeHolderResId = R.color.black,errorResId = R.color.blue,isAnim = false,
63-
requestListener = {
64-
...
65-
},
66-
onProgressListener = {
67-
...
68-
}, transformation = *arrayOf(GrayscaleTransformation())
69-
)
70152
```
71153

72-
## 可选扩展函数Api
154+
## Kotlin DSL
155+
156+
DSL的编写可以用下面代码简单理解和记忆(主要参考:[如何让你的回调更具Kotlin风味 (juejin.cn)](https://juejin.cn/post/6844903769436585991)
157+
158+
```kotlin
159+
class DSLTest{
160+
//普通变量
161+
var str:String? =null
162+
//函数变量
163+
var onSuccess: ((String?) -> Unit)? = null
164+
//调用函数变量
165+
fun onSuccessDo() {
166+
...
167+
onSuccess.invoke("success $str")
168+
}
169+
}
170+
//定义调用的函数
171+
load(dslPar:(DSLTest.() -> Unit)? = null){
172+
DSLTest().also(dslPar)
173+
}
174+
//使用
175+
load{
176+
str = "ACC"
177+
onSuccess{
178+
//TODO
179+
}
180+
}
181+
```
182+
183+
## 与传统策略模式封装对比
184+
185+
- 定义策略模式基础接口
186+
187+
```kotlin
188+
/** 图片加载策略 接口*/
189+
public interface BaseImageLoaderStrategy {
190+
void loadImage(load Any,ImageOptions options);
191+
}
192+
```
193+
194+
- 实现策略接口
195+
196+
```kotlin
197+
/*** 具体的加载策略, Glide 加载框架*/
198+
public class GlideImageLoader implements BaseImageLoaderStrategy {
199+
@Override
200+
public void loadImage(Context context, ImageOptions options) {
201+
Glide.with(context).apply(...).into(options.getImgView());
202+
}
203+
}
204+
```
205+
206+
- 策略调度器调用
207+
208+
```kotlin
209+
ImageLoader.loadImage(ImageOptions(imageView).apply{
210+
.....
211+
})
212+
```
213+
214+
策略模式一般会封装很多接口满足日常需求,由于kotlin特性我们封装一个超长参数的方法,然后使用可选参数的方式调用,但是java就无能为力了,只能对可选参数赋值null。
215+
216+
```kotlin
217+
//可选参数示例
218+
load(url:String,isCirle:Boolean = false, width:Int=0, height:Int = 0){
219+
.....
220+
}
221+
//用 参数名 = 值 使用可选参数
222+
iv_8.load(url2, height = 800)
223+
```
224+
225+
策略模式封装写法和扩展函数+DSL写法对比:
226+
227+
- 统一的接口封装,都具有可扩展性
228+
- 都可以用kotlin特性不用定义大量接口
229+
- 扩展函数更加方便简洁
230+
- DSL的写法让代码更加易懂,更具kotlin风格
231+
- 多方法接口回调,可以只选择个别方法
232+
233+
## 总结
234+
235+
- 最后要方便的使用到项目中那就打包发布jitpack仓库,项目开源地址和文档
236+
237+
[forJrking/ImageExt: 基于Glide封装ImageView加载图片资源的扩展函数集 (github.com)](https://github.com/forJrking/ImageExt)
238+
239+
- 由于使用到基于okhttp的下载进度管理所以使用了 glide 的@GlideModule配置方法,这样可能会和你项目自定义配置有冲突,目前只能拉代码自己修改,然后依赖Module方式了。如有更好方式联系我改进。
240+
241+
- Android图片加载库常见的只有几种,其他库可以自行参考实现。Kotlin真香!!!
242+
243+
244+
## 可选配置
73245

74246
```kotlin
75-
ImageView.loadImage(...)
76-
ImageView.loadProgressImage(...)
77-
ImageView.loadResizeImage(...)
78-
ImageView.loadGrayImage(...)
79-
ImageView.loadBlurImage(...)
80-
ImageView.loadBlurImage(...)
81-
ImageView.loadRoundCornerImage(...)
82-
ImageView.loadCircleImage(...)
83-
ImageView.loadBorderImage(...)
84-
ImageView.load(load: Any?, options: ImageOptions.() -> Unit)//DSL
85247

86248
//终极扩展函数 选用dsl方式
87-
@JvmOverloads
88-
fun ImageView.loadImage(load: Any?, with: Any? = this,
249+
(load: Any?, with: Any? = this,
89250
//占位图 错误图
90251
@DrawableRes placeHolderResId: Int = placeHolderImageView, placeHolderDrawable: Drawable? = null,
91252
@DrawableRes errorResId: Int = placeHolderImageView, errorDrawable: Drawable? = null,
@@ -116,7 +277,7 @@ isRoundedCorners: Boolean = false, roundRadius: Int = 0, cornerType: ImageOption
116277
//自定义转换器
117278
vararg transformation: Transformation<Bitmap>,
118279
//进度监听,请求回调监听
119-
onProgressListener: OnProgressListener? = null, requestListener: OnImageListener? = null) {...}
280+
onProgressListener: OnProgressListener? = null, requestListener: OnImageListener? = null
120281
```
121282

122283
## CircleProgressView 仿微博图片加载

0 commit comments

Comments
 (0)