如何解决如何更改通过Html.fromHtmltext跨接在TextView中加载的默认图像占位符
我的应用程序上有一个新闻部分,该部分从我的网站加载一些新闻,其中一些包含图片,因此我从互联网上加载它们。但是,当未加载图片时,会有一个绿色方块,只有在加载图片时才会消失。
未加载图片:
然后加载图片:
我想使绿色正方形不可见。
为简单起见,我们假设我什至不加载图像,只是想使绿色正方形不可见,而不用空文本替换图像标签。
代码:
val exampleText = "Example <br> <img src=\"https://www.w3schools.com/images/w3schools_green.jpg\" alt=\"W3Schools.com\"> <br> Example"
tv_body.text = fromHtml(exampleText)
fun fromHtml(html: String?): Spanned? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Html.fromHtml(html,Html.FROM_HTML_MODE_LEGACY);
} else {
Html.fromHtml(html);
}
}
我的解决方法:
private var drawable: Drawable? = null
fun fromHtml(context: Activity?,tv: TextView?,text: String?) {
if (TextUtils.isEmpty(text) || context == null || tv == null) return
//Replace all image tags with an empty text
val noImageText = text!!.replace("<img.*?>".toRegex(),"")
//Set the textview text with the imageless html
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
tv.text = Html.fromHtml(noImageText,Html.FROM_HTML_MODE_LEGACY)
} else {
tv.text = Html.fromHtml(noImageText)
}
Thread {
//Creating the imageGetter
val imageGetter = ImageGetter { url ->
drawable = getimageFromNetwork(url)
if (drawable != null) {
var w = drawable!!.intrinsicWidth
var h = drawable!!.intrinsicHeight
// Scaling the width and height
if (w < h && h > 0) {
val scale = 400.0f / h
w = (scale * w).toInt()
h = (scale * h).toInt()
} else if (w > h && w > 0) {
val scale = 1000.0f / w
w = (scale * w).toInt()
h = (scale * h).toInt()
}
drawable!!.setBounds(0,w,h)
} else if (drawable == null) {
return@ImageGetter null
}
drawable!!
}
val textWithImage = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Html.fromHtml(text,Html.FROM_HTML_MODE_LEGACY,imageGetter,null)
} else {
Html.fromHtml(text,null)
}
// update runOnUiThread and change the textview text from the textWithoutimage to the textWithImage
context.runOnUiThread(Runnable { tv.text = textWithImage })
}.start()
}
private fun getimageFromNetwork(imageUrl: String): Drawable? {
var myFileUrl: URL? = null
var drawable: Drawable? = null
try {
myFileUrl = URL(imageUrl)
val conn = myFileUrl
.openConnection() as HttpURLConnection
conn.doInput = true
conn.connect()
val `is` = conn.inputStream
drawable = Drawable.createFromStream(`is`,null)
`is`.close()
} catch (e: Exception) {
e.printstacktrace()
return null
}
return drawable
}
所以当我打电话给这个
val exampleText = "Example <br> <img src=\"https://www.w3schools.com/images/w3schools_green.jpg\" alt=\"W3Schools.com\"> <br> Example"
fromHtml((activity as NewsActivity?),tv_body,exampleText)
它首先显示了这一点:
我仍然认为制作无图像的文字不是解决方案,而是适当的解决方案,我认为可能更简单一些:
<style name="LIGHT" parent="Theme.AppCompat.DayNight.DarkActionBar">
<item name="android:placeHolderDefaultimage">@drawable/invisible</item>
因此,绿色方块将是一个不可见的可绘制对象,尽管我真的不知道如何更改该默认占位符图像,但我不需要设置两次html文本。猜猜我会坚持解决方法
解决方法
您看到的占位符图像来自 com.android.internal.R.drawable.unknown_image ,并且如果 ImageGetter 返回null则设置该图像。来自HTML中的函数startImg()。
private static void startImg(Editable text,Attributes attributes,Html.ImageGetter img) {
...
if (d == null) {
d = Resources.getSystem().
getDrawable(com.android.internal.R.drawable.unknown_image);
d.setBounds(0,d.getIntrinsicWidth(),d.getIntrinsicHeight());
}
....
}
因此,您在原始代码中的某个地方从 ImageGetter 返回了null。由于未知的可绘制图像是硬编码的,因此无法通过样式或主题进行触摸。如果您想解决的话,您也许可以做一些反思。
我建议不要包装从 ImageGetter 返回的drawable,以便可以在不直接操作文本的情况下更改图像,而不是在下载的图像可用之前或之后处理HTML文本。最初,包装器将包含占位符图像,随后,包装器将包含可用的下载图像。
这里有一些示例代码显示了此技术。占位符是显示的可绘制对象,但可以是您想要的任何对象。我使用可见的可绘制对象(Html.java中的默认对象,但“空”中带有“ E”)来显示它确实可以显示并且可以更改。您可以提供透明的可绘制对象,以使其不显示任何内容。
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var tvBody: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
tvBody = findViewById(R.id.tv_body)
val exampleText =
"Example <br> <img src=\"https://www.w3schools.com/images/w3schools_green.jpg\" alt=\"W3Schools.com\"> <br> Example"
tvBody.text = fromHtml(exampleText,this)
}
private fun fromHtml(html: String?,context: Context): Spanned? {
// Define the ImageGetter for Html. The default "no image,yet" drawable is
// R.drawable.placeholder but can be another drawable.
val imageGetter = Html.ImageGetter { url ->
val d = ContextCompat.getDrawable(context,R.drawable.placeholder) as BitmapDrawable
// Simulate a network fetch of the real image we want to display.
ImageWrapper(d).apply {
simulateNetworkFetch(context,this,url)
}
}
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Html.fromHtml(html,Html.FROM_HTML_MODE_LEGACY,imageGetter,null)
} else {
Html.fromHtml(html,null)
}
}
private fun simulateNetworkFetch(context: Context,imageWrapper: ImageWrapper,url: String) {
GlobalScope.launch {
Log.d("Applog","Simulating fetch of $url")
// Just wait for a busy network to get back to us.
delay(4000)
// Get the "downloaded" image and place it in our image wrapper.
val d = ContextCompat.getDrawable(context,R.drawable.downloaded) as BitmapDrawable
imageWrapper.setBitmapDrawable(d)
// Force a remeasure/relayout of the TextView with the new image.
this@MainActivity.runOnUiThread {
tvBody.text = tvBody.text
}
}
}
// Simple wrapper for a BitmapDrawable.
private class ImageWrapper(d: BitmapDrawable) : Drawable() {
private lateinit var mBitMapDrawable: BitmapDrawable
init {
setBitmapDrawable(d)
}
override fun draw(canvas: Canvas) {
mBitMapDrawable.draw(canvas)
}
override fun setAlpha(alpha: Int) {
}
override fun setColorFilter(colorFilter: ColorFilter?) {
}
override fun getOpacity(): Int {
return PixelFormat.OPAQUE
}
fun setBitmapDrawable(bitmapDrawable: BitmapDrawable) {
mBitMapDrawable = bitmapDrawable
mBitMapDrawable.setBounds(
0,mBitMapDrawable.intrinsicWidth,mBitMapDrawable.intrinsicHeight
)
setBounds(mBitMapDrawable.bounds)
}
}
}
这是它在模拟器中的外观:
示例项目为here,其中包括对API 23+使用 DrawableWrapper 的方法,IMO更加整洁。上面的代码也可以正常工作。不幸的是, DrawableWrapper 的 AppCompat 版本受到限制。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。