Skip to content

Commit 7cd6221

Browse files
feat(*): 添加加载图文混排html格式文本工具类
1 parent d6dac52 commit 7cd6221

File tree

1 file changed

+145
-0
lines changed

1 file changed

+145
-0
lines changed
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
package com.pengxh.kt.lite.utils
2+
3+
import android.content.Context
4+
import android.os.Build
5+
import android.text.Editable
6+
import android.text.Html
7+
import android.text.Spanned
8+
import android.text.method.LinkMovementMethod
9+
import android.text.style.ClickableSpan
10+
import android.text.style.ImageSpan
11+
import android.view.View
12+
import android.widget.TextView
13+
import androidx.lifecycle.Lifecycle
14+
import androidx.lifecycle.LifecycleOwner
15+
import androidx.lifecycle.LifecycleRegistry
16+
import androidx.lifecycle.lifecycleScope
17+
import com.bumptech.glide.Glide
18+
import com.pengxh.kt.lite.extensions.getScreenWidth
19+
import kotlinx.coroutines.Dispatchers
20+
import kotlinx.coroutines.launch
21+
import kotlinx.coroutines.withContext
22+
import org.xml.sax.XMLReader
23+
import java.util.Locale
24+
25+
class HtmlRenderEngine : LifecycleOwner {
26+
private val kTag = "HtmlRenderEngine"
27+
private val registry = LifecycleRegistry(this)
28+
private lateinit var context: Context
29+
private lateinit var html: String
30+
private lateinit var textView: TextView
31+
private lateinit var imageSourceListener: OnGetImageSourceListener
32+
33+
/**
34+
* 设置上下文
35+
* */
36+
fun setContext(context: Context): HtmlRenderEngine {
37+
this.context = context
38+
return this
39+
}
40+
41+
/**
42+
* 设置html格式的文本
43+
* */
44+
fun setHtmlContent(html: String): HtmlRenderEngine {
45+
this.html = html
46+
return this
47+
}
48+
49+
/**
50+
* 设置显示html格式文本的View
51+
* */
52+
fun setTargetView(textView: TextView): HtmlRenderEngine {
53+
this.textView = textView
54+
return this
55+
}
56+
57+
/**
58+
* 设置html里面图片地址回调监听
59+
* */
60+
fun setOnGetImageSourceListener(imageSourceListener: OnGetImageSourceListener): HtmlRenderEngine {
61+
this.imageSourceListener = imageSourceListener
62+
return this
63+
}
64+
65+
fun load() {
66+
if (html.isBlank()) {
67+
return
68+
}
69+
lifecycleScope.launch(Dispatchers.Main) {
70+
textView.movementMethod = LinkMovementMethod.getInstance()
71+
//默认不处理图片先这样简单设置
72+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
73+
textView.text = Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY)
74+
} else {
75+
textView.text = Html.fromHtml(html)
76+
}
77+
withContext(Dispatchers.IO) {
78+
val imageGetter = Html.ImageGetter { source ->
79+
val drawable = Glide.with(context).load(source).submit().get()
80+
var width = drawable.intrinsicWidth
81+
var height = drawable.intrinsicHeight
82+
83+
//对图片按比例缩放尺寸
84+
val scale = context.getScreenWidth() / width.toFloat()
85+
width = (scale * width).toInt()
86+
height = (scale * height).toInt()
87+
drawable.setBounds(0, 0, width, height)
88+
//return
89+
drawable
90+
}
91+
92+
val htmlText = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
93+
Html.fromHtml(
94+
html, Html.FROM_HTML_MODE_LEGACY, imageGetter, object : Html.TagHandler {
95+
override fun handleTag(
96+
opening: Boolean, tag: String,
97+
output: Editable, xmlReader: XMLReader
98+
) {
99+
if (tag.lowercase(Locale.getDefault()) == "img") {
100+
val len = output.length
101+
val images = output.getSpans(
102+
len - 1, len, ImageSpan::class.java
103+
)
104+
val imgSource = images[0].source ?: return
105+
output.setSpan(object : ClickableSpan() {
106+
override fun onClick(widget: View) {
107+
imageSourceListener.imageSource(imgSource)
108+
}
109+
}, len - 1, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
110+
}
111+
}
112+
})
113+
} else {
114+
Html.fromHtml(html, imageGetter, object : Html.TagHandler {
115+
override fun handleTag(
116+
opening: Boolean, tag: String, output: Editable, xmlReader: XMLReader
117+
) {
118+
if (tag.lowercase(Locale.getDefault()) == "img") {
119+
val len = output.length
120+
val images = output.getSpans(len - 1, len, ImageSpan::class.java)
121+
val imgSource = images[0].source ?: return
122+
output.setSpan(object : ClickableSpan() {
123+
override fun onClick(widget: View) {
124+
imageSourceListener.imageSource(imgSource)
125+
}
126+
}, len - 1, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
127+
}
128+
}
129+
})
130+
}
131+
withContext(Dispatchers.Main) {
132+
textView.text = htmlText
133+
}
134+
}
135+
}
136+
}
137+
138+
interface OnGetImageSourceListener {
139+
fun imageSource(url: String)
140+
}
141+
142+
override fun getLifecycle(): Lifecycle {
143+
return registry
144+
}
145+
}

0 commit comments

Comments
 (0)