如何更改通过Html.fromHtml(text)跨接在TextView中加载的默认图像(占位符)

我的应用程序上有一个新闻部分,该部分从我的网站加载一些新闻,其中一些包含图片,因此我从互联网上加载它们。但是,当未加载图片时,会有一个绿色方块,只有在加载图片时才会消失。

未加载图片:

如何更改通过Html.fromHtml(text)跨接在TextView中加载的默认图像(占位符)

然后加载图片:

如何更改通过Html.fromHtml(text)跨接在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);
    }
}

有没有一种方法可以更改默认图像而不进行任何欺骗?

我的解决方法:

我要做的就是改编自定义的fromHtml函数。

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)

它首先显示了这一点:

如何更改通过Html.fromHtml(text)跨接在TextView中加载的默认图像(占位符)

(因为我用空文本替换了图片标签)

然后在图像加载时显示以下内容:

如何更改通过Html.fromHtml(text)跨接在TextView中加载的默认图像(占位符)

我仍然认为制作无图像的文字不是解决方案,而是适当的解决方案,我认为可能更简单一些:

<style name="LIGHT" parent="Theme.AppCompat.DayNight.DarkactionBar">
    <item name="android:placeHolderDefaultImage">@drawable/invisible</item>

因此,绿色方块将是一个不可见的可绘制对象,尽管我真的不知道如何更改该默认占位符图像,但我不需要设置两次html文本。猜猜我会坚持解决方法

wdd16617723 回答:如何更改通过Html.fromHtml(text)跨接在TextView中加载的默认图像(占位符)

您看到的占位符图像来自 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)
        }
    }
}

这是它在模拟器中的外观:

enter image description here


示例项目为here,其中包括对API 23+使用 DrawableWrapper 的方法,IMO更加整洁。上面的代码也可以正常工作。不幸的是, DrawableWrapper AppCompat 版本受到限制。

本文链接:https://www.f2er.com/1279186.html

大家都在问