ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

原来Span可以这样加载网络图(下),Flutter中网络图片加载和缓存源码分析

2022-01-27 18:33:45  阅读:362  来源: 互联网

标签:Span val request private 源码 fun return textView 加载


}

这里对textView使用弱引用,避免内存泄漏。然后定义一个图片加载接口,用来处理这个请求。

interface DrawableProvider {
fun get(request: URLImageSpanRequest): Drawable
}

这里我用了Glide来加载图片。

class GlideDrawableProvider : DrawableProvider {
override fun get(request: URLImageSpanRequest): Drawable {
val drawable = if (request.url.isNullOrEmpty()) {
request.placeholderDrawable ?: request.errorPlaceholder
} else {
execute(request)
request.placeholderDrawable
}
return drawable ?: ColorDrawable()/Can’t be null/
}

fun execute(request: URLImageSpanRequest) {
val view = request.view ?: return
val span = request.span
Glide.with(view)
.load(request.url)
.error(request.errorPlaceholder)
.override(request.desiredWidth, request.desiredHeight)
.into(object : CustomTarget() {
override fun onResourceReady(
resource: Drawable,
transition: Transition?
) {
resource.setBounds(0, 0, resource.intrinsicWidth, resource.intrinsicHeight)
onResponse(request, resource)
}

override fun onl oadFailed(errorDrawable: Drawable?) {
if (errorDrawable != null) {
onResponse(request, errorDrawable)
}
}

override fun onl oadCleared(placeholder: Drawable?) {
}

private fun onResponse(request: URLImageSpanRequest, drawable: Drawable) {
val spannable = request.view?.text as? Spannable ?: return
spannable.replaceSpan(
span,
ImageSpan(drawable, request.verticalAlignment),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
})
}

fun Spannable.replaceSpan(oldSpan: Any?, newSpan: Any?, flags: Int): Boolean {
if (oldSpan == null || newSpan == null) {
return false
}
val start = getSpanStart(oldSpan)
val end = getSpanEnd(oldSpan)
if (start == -1 || end == -1) {
return false
}
removeSpan(oldSpan)
setSpan(newSpan, start, end, flags)
return true
}
}

如果url是空的话就没必要开启图片加载了。get()方法的返回值是占位图。图片加载后替换占位Span。

最后用Builder模式将上面的内容组合一下

class URLImageSpan {
open class Builder(private val provider: DrawableProvider = GlideDrawableProvider()) {
private var url: String? = null
private var placeholderDrawable: Drawable? = null
private var placeholderId = 0
private var useInstinctPlaceholderSize = true
private var errorPlaceholder: Drawable? = null
private var errorId = 0
private var useInstinctErrorPlaceholderSize = true
private var verticalAlignment = DynamicDrawableSpan.ALIGN_BOTTOM
private var desiredWidth = -1
private var desiredHeight = -1

fun override(width: Int, height: Int): Builder {
this.desiredWidth = width
this.desiredHeight = height
return this
}

fun url(url: String?): Builder {
this.url = url
r
eturn this
}

fun placeholder(drawable: Drawable?): Builder {
this.placeholderDrawable = drawable
this.placeholderId = 0
this.useInstinctPlaceholderSize = true
return this
}

fun error(drawable: Drawable?): Builder {
this.errorPlaceholder = drawable
this.errorId = 0
this.useInstinctErrorPlaceholderSize = true
return this
}

fun buildRequest(textView: TextView): URLImageSpanRequest {
val context = textView.context
return URLImageSpanRequest(
textView = textView,
url = url,
placeholderDrawable = getPlaceholderDrawable(context),
errorPlaceholder = getErrorDrawable(context),
verticalAlignment = verticalAlignment,
desiredWidth = desiredWidth,
desiredHeight = desiredHeight
)
}

fun build(textView: TextView): DynamicDrawableSpan {
val request = buildRequest(textView)
return object : DynamicDrawableSpan() {
override fun getDrawable(): Drawable {
request.span = this
return provider.get(request)
}
}
}
}
}

注意记得将占位span赋值。见上面的build()方法

封装后的使用方式

val ss =
SpannableString(“To be or not to be, that is the question(生存还是毁灭,这是一个值得考虑的问题)”)
val urlImageSpan = URLImageSpan.Builder()
.url(“https://sf6-ttcdn-tos.pstatp.com/img/user-avatar/d8111dfb52a63f3f12739194cf367754~500x500.png”)
.override(100.dp, 100.dp)
.build(textView)
ss.setSpan(urlImageSpan, 0, 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
textView.setText(ss, TextView.BufferType.SPANNABLE) // 必需设置

与之前的用法对比,明显简单了不少

val ss = SpannableStringBuilder(“To be or not to be, that is the question(生存还是毁灭,这是一个值得考虑的问题)”)
val placeholderSpan = ImageSpan(context, R.mipmap.placeholder)
ss.setSpan(placeholderSpan, 0, 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
textView.setText(ss, TextView.BufferType.SPANNABLE) // 必需设置
val spannable = textView.text as? Spannable ?: return
Glide.with(textView)
.load(“https://sf6-ttcdn-tos.pstatp.com/img/user-avatar/d8111dfb52a63f3f12739194cf367754~100x100.png”)
.into(object : CustomTarget() {
override fun onResourceReady(resource: Drawable, transition: Transition?) {
val start = spannable.getSpanStart(placeholderSpan)
val end = spannable.getSpanEnd(placeholderSpan)
if (start != -1 && end != -1) {// 替换Span
ion: Transition?) {
val start = spannable.getSpanStart(placeholderSpan)
val end = spannable.getSpanEnd(placeholderSpan)
if (start != -1 && end != -1) {// 替换Span

标签:Span,val,request,private,源码,fun,return,textView,加载
来源: https://blog.csdn.net/m0_66264910/article/details/122722058

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有