有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何更改文本视图中通过Html加载的默认图像(占位符)。fromHtml(文本)

我的应用程序上有一个新闻部分,从我的网站加载一些新闻,其中一些包含图片,所以我从互联网加载它们。但是,虽然没有加载图像,但只有在加载图像时才会出现一个绿色正方形

未加载图像:

Little green square

然后加载图像:

Image loaded

我想让那个绿色的正方形隐形

为了简单起见,让我们假设我甚至不加载图像,只想使绿色的方块不可见,而不使用空文本替换图像标记

代码:

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, 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, imageGetter, 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)

它首先表明:

imageless textview

(因为我用空文本替换了图像标记)

然后,当图像加载时,它显示以下内容:

Image properly displayed

我仍然认为制作无图像文本与其说是一个合适的解决方案,不如说是一个解决方案,我认为可能有一些更简单的方法,比如:

<style name="LIGHT" parent="Theme.AppCompat.DayNight.DarkActionBar">
    <item name="安卓:placeHolderDefaultImage">@drawable/invisible</item>

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


共 (1) 个答案

  1. # 1 楼答案

    您看到的占位符图像来自com。安卓内部的R.可牵引。未知的\u图像,如果ImageGetter返回空值,则设置该图像。从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, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
        }
        ....
    }
    

    因此,在原始代码的某个地方,您从ImageGetter返回一个null。因为未知的可绘制图像是硬编码的,所以不能通过样式或主题来触及它。如果你想解决某件事,你可以通过反思来做一些事情

    与其在下载的图像可用之前或之后操作HTML文本,我建议对从ImageGetter返回的drawable进行包装,以便在不直接操作文本的情况下更改图像。最初,包装器将包含占位符图像,稍后,包装器将包含可用的下载图像

    下面是一些显示这种技术的示例代码。占位符是一个可绘制的显示,但它可以是您想要的任何内容。我使用一个可见的drawable(Html.java中的默认值,但带有一个“E”表示“empty”。)以显示它确实显示并且可以更改。您可以提供一个透明的绘图板,以便不显示任何内容

    主要活动。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, imageGetter, 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,
                    0,
                    mBitMapDrawable.intrinsicWidth,
                    mBitMapDrawable.intrinsicHeight
                )
                setBounds(mBitMapDrawable.bounds)
            }
        }
    }
    

    以下是它在模拟器中的外观:

    enter image description here


    示例项目是here,其中包括对API 23+使用DrawableWrapper,依我看,这有点整洁。上面的代码同样有效。不幸的是,DrawableWrapperAppCompat版本受到限制