📜  如何在Android中以Textview格式显示HTML和图像?

📅  最后修改于: 2021-05-08 20:57:42             🧑  作者: Mango

在某些情况下,您需要在应用程序中显示格式丰富的文本,例如博客应用程序或Quora之类的应用程序,但Android的内置函数默认情况下不允许显示嵌入式图像,而且它们会在屏幕上显示难看的蓝线在blockquote标记内的任何内容的左侧。这是在TextView中显示HTML以及在Android中显示图像的简单解决方案。请注意,我们将在Android中使用Kotlin语言实现此项目。以下是该应用程序的演示屏幕截图。

演示

先决条件

  • 协程库的基本知识。
  • 毕加索图书馆的基本知识。

方法

步骤1:创建一个新项目

要在Android Studio中创建新项目,请参阅如何在Android Studio中创建/启动新项目请注意,选择Kotlin作为编程语言。

步骤2:编码前的专案设定

  • colors.xml文件中添加一些颜色。此处的颜色用于块引用样式。您可以自由选择不同的颜色。
colors.xml


    #0F9D58
    #0F9D58
    #03DAC5
    #878585


activity_main.xml


  
  
    
    
  
    
    


ImageGetter.kt
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.text.Html
import android.widget.TextView
import com.squareup.picasso.Picasso
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
  
// Class to download Images which extends [Html.ImageGetter]
class ImageGetter(
    private val res: Resources,
    private val htmlTextView: TextView
) : Html.ImageGetter {
  
    // Function needs to overridden when extending [Html.ImageGetter] ,
    // which will download the image
    override fun getDrawable(url: String): Drawable {
        val holder = BitmapDrawablePlaceHolder(res, null)
  
        // Coroutine Scope to download image in Background
        GlobalScope.launch(Dispatchers.IO) {
            runCatching {
  
                // downloading image in bitmap format using [Picasso] Library
                val bitmap = Picasso.get().load(url).get()
                val drawable = BitmapDrawable(res, bitmap)
  
                // To make sure Images don't go out of screen , Setting width less
                // than screen width, You can change image size if you want
                val width = getScreenWidth() - 150
  
                // Images may stretch out if you will only resize width,
                // hence resize height to according to aspect ratio
                val aspectRatio: Float =
                    (drawable.intrinsicWidth.toFloat()) / (drawable.intrinsicHeight.toFloat())
                val height = width / aspectRatio
                drawable.setBounds(10, 20, width, height.toInt())
                holder.setDrawable(drawable)
                holder.setBounds(10, 20, width, height.toInt())
                withContext(Dispatchers.Main) {
                    htmlTextView.text = htmlTextView.text
                }
            }
        }
        return holder
    }
  
    // Actually Putting images
    internal class BitmapDrawablePlaceHolder(res: Resources, bitmap: Bitmap?) :
        BitmapDrawable(res, bitmap) {
        private var drawable: Drawable? = null
  
        override fun draw(canvas: Canvas) {
            drawable?.run { draw(canvas) }
        }
  
        fun setDrawable(drawable: Drawable) {
            this.drawable = drawable
        }
    }
  
    // Function to get screenWidth used above
    fun getScreenWidth() =
        Resources.getSystem().displayMetrics.widthPixels
}


MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
  
        // Click Listener to listner button click events.
        // display_html is button id from activity_main.xml 
        // You don't need to get reference to it because koltin 
        // provides synthetic import and 
        // We are gonna use for the same for rest of Views
        display_html.setOnClickListener {
            if (editor.text.isNotEmpty()) {
                displayHtml(editor.text.toString())
            }
        }
    }
}


Kotlin
private fun displayHtml(html: String) {
    
      // Creating object of ImageGetter class you just created
      val imageGetter = ImageGetter(resources, html_viewer)
       
      // Using Html framework to parse html
      val styledText=HtmlCompat.fromHtml(html, 
                                         HtmlCompat.FROM_HTML_MODE_LEGACY,
                                         imageGetter,null)
         
      // to enable image/link clicking
      html_viewer.movementMethod = LinkMovementMethod.getInstance()
        
      // setting the text after formatting html and downloadig and setting images
      html_viewer.text = styledText
  }


Kotlin
import android.os.Bundle
import android.text.method.LinkMovementMethod
import androidx.appcompat.app.AppCompatActivity
import androidx.core.text.HtmlCompat
import kotlinx.android.synthetic.main.activity_main.*
  
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
  
        // Click Listener to listner button click events.
        // display_html is button id from activity_main.xml 
        // You don't need to get reference to it 
        // because koltin provides synthetic import and 
        // We are gonna use for the same for rest of Views
        display_html.setOnClickListener {
            if (editor.text.isNotEmpty()) {
                displayHtml(editor.text.toString())
            }
        }
    }
  
    private fun displayHtml(html: String) {
        // Creating object of ImageGetter class you just created
        val imageGetter = ImageGetter(resources, html_viewer)
  
        // Using Html framework to parse html
        val styledText =
            HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY, imageGetter,null)
  
        // to enable image/link clicking
        html_viewer.movementMethod = LinkMovementMethod.getInstance()
  
        // setting the text after formatting html and downloadig and setting images
        html_viewer.text = styledText
    }
}


QuoteSpanClass.kt
import android.graphics.Canvas
import android.graphics.Paint
import android.text.Layout
import android.text.style.LeadingMarginSpan
import android.text.style.LineBackgroundSpan
  
class QuoteSpanClass(
    private val backgroundColor: Int,
    private val stripeColor: Int,
    private val stripeWidth: Float,
    private val gap: Float
) : LeadingMarginSpan, LineBackgroundSpan {
      
    // Margin for the block quote tag
    override fun getLeadingMargin(first: Boolean): Int {
        return (stripeWidth + gap).toInt()
    }
  
    // this function draws the margin.
    override fun drawLeadingMargin(
        c: Canvas,
        p: Paint,
        x: Int,
        dir: Int,
        top: Int,
        baseline: Int,
        bottom: Int,
        text: CharSequence,
        start: Int,
        end: Int,
        first: Boolean,
        layout: Layout
    ) {
  
        val style = p.style
        val paintColor = p.color
        p.style = Paint.Style.FILL
        p.color = stripeColor
  
        // Creating margin according to color and stripewidth it recieves
        // Press CTRL+Q on function name to read more
        c.drawRect(x.toFloat(), top.toFloat(), x + dir * stripeWidth, bottom.toFloat(), p)
        p.style = style
        p.color = paintColor
    }
  
    override fun drawBackground(
        c: Canvas,
        p: Paint,
        left: Int,
        right: Int,
        top: Int,
        baseline: Int,
        bottom: Int,
        text: CharSequence,
        start: Int,
        end: Int,
        lnum: Int
    ) {
        val paintColor = p.color
        p.color = backgroundColor
  
        // It draws the background on which blockquote text is written
        c.drawRect(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat(), p)
        p.color = paintColor
    }
}


MainActivity.kt
private fun replaceQuoteSpans(spannable: Spannable) 
{
  val quoteSpans: Array = 
      spannable.getSpans(0, spannable.length - 1, QuoteSpan::class.java)
  
  for (quoteSpan in quoteSpans) 
  {
    val start: Int = spannable.getSpanStart(quoteSpan)
    val end: Int = spannable.getSpanEnd(quoteSpan)
    val flags: Int = spannable.getSpanFlags(quoteSpan)
    spannable.removeSpan(quoteSpan)
       spannable.setSpan(
               QuoteSpanClass(
                    // background color
                    ContextCompat.getColor(this, R.color.colorPrimary),  
                    // strip color
                    ContextCompat.getColor(this, R.color.colorAccent),
                    // strip width
                    10F, 50F
                ),
                start, end, flags
            )
        }   
  }


Kotlin
import android.os.Bundle
import android.text.Spannable
import android.text.method.LinkMovementMethod
import android.text.style.QuoteSpan
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.text.HtmlCompat
import kotlinx.android.synthetic.main.activity_main.*
  
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
  
        // Click Listener to listner button click events.
        // display_html is button id from activity_main.xml 
        // You don't need to get reference to it
        // because koltin provides synthetic import and
        // We are gonna use for the same for rest of Views
        display_html.setOnClickListener {
            if (editor.text.isNotEmpty()) {
                displayHtml(editor.text.toString())
            }
        }
    }
  
    private fun displayHtml(html: String) {
        // Creating object of ImageGetter class you just created
        val imageGetter = ImageGetter(resources, html_viewer)
  
        // Using Html framework to parse html
        val styledText =
            HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY, imageGetter,null)
  
        replaceQuoteSpans(styledText as Spannable)
  
        // setting the text after formatting html and downloadig and setting images
        html_viewer.text = styledText
  
        // to enable image/link clicking
        html_viewer.movementMethod = LinkMovementMethod.getInstance()
  
    }
  
    private fun replaceQuoteSpans(spannable: Spannable)
    {
        val quoteSpans: Array =
            spannable.getSpans(0, spannable.length - 1, QuoteSpan::class.java)
  
        for (quoteSpan in quoteSpans)
        {
            val start: Int = spannable.getSpanStart(quoteSpan)
            val end: Int = spannable.getSpanEnd(quoteSpan)
            val flags: Int = spannable.getSpanFlags(quoteSpan)
            spannable.removeSpan(quoteSpan)
            spannable.setSpan(
                QuoteSpanClass(
                    // background color
                    ContextCompat.getColor(this, R.color.colorPrimary),
                    // strip color
                    ContextCompat.getColor(this, R.color.colorAccent),
                    // strip width
                    10F, 50F
                ),
                start, end, flags
            )
        }
    }
}


Kotlin
// Function to parse image tags and enable click events
fun ImageClick(html: Spannable) 
{
  for (span in html.getSpans(0, html.length, ImageSpan::class.java))
  {
    val flags = html.getSpanFlags(span)
    val start = html.getSpanStart(span)
    val end = html.getSpanEnd(span)
    html.setSpan(object : URLSpan(span.source) {
         override fun onClick(v: View) {
                Log.d(TAG, "onClick: url is ${span.source}")
            }
  }, start, end, flags)
}


Kotlin
import android.os.Bundle
import android.text.Spannable
import android.text.method.LinkMovementMethod
import android.text.style.ImageSpan
import android.text.style.QuoteSpan
import android.text.style.URLSpan
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.text.HtmlCompat
import kotlinx.android.synthetic.main.activity_main.*
  
private const val TAG="MainActivity"
  
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
  
        // Click Listener to listner button click events.
        // display_html is button id from activity_main.xml 
        // You don't need to get reference to it
        // because koltin provides synthetic import and
        // We are gonna use for the same for rest of Views
        display_html.setOnClickListener {
            if (editor.text.isNotEmpty()) {
                displayHtml(editor.text.toString())
            }
        }
    }
  
    private fun displayHtml(html: String) {
        // Creating object of ImageGetter class you just created
        val imageGetter = ImageGetter(resources, html_viewer)
  
        // Using Html framework to parse html
        val styledText =
            HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY, imageGetter, null)
  
        replaceQuoteSpans(styledText as Spannable)
        ImageClick(styledText as Spannable)
  
        // setting the text after formatting html and downloadig and setting images
        html_viewer.text = styledText
  
        // to enable image/link clicking
        html_viewer.movementMethod = LinkMovementMethod.getInstance()
  
    }
  
    private fun replaceQuoteSpans(spannable: Spannable) {
        val quoteSpans: Array =
            spannable.getSpans(0, spannable.length - 1, QuoteSpan::class.java)
  
        for (quoteSpan in quoteSpans) {
            val start: Int = spannable.getSpanStart(quoteSpan)
            val end: Int = spannable.getSpanEnd(quoteSpan)
            val flags: Int = spannable.getSpanFlags(quoteSpan)
            spannable.removeSpan(quoteSpan)
            spannable.setSpan(
                QuoteSpanClass(
                    // background color
                    ContextCompat.getColor(this, R.color.colorPrimary),
                    // strip color
                    ContextCompat.getColor(this, R.color.colorAccent),
                    // strip width
                    10F, 50F
                ),
                start, end, flags
            )
        }
    }
  
    // Function to parse image tags and enable click events
    fun ImageClick(html: Spannable) {
        for (span in html.getSpans(0, html.length, ImageSpan::class.java)) {
            val flags = html.getSpanFlags(span)
            val start = html.getSpanStart(span)
            val end = html.getSpanEnd(span)
            html.setSpan(object : URLSpan(span.source) {
                override fun onClick(v: View) {
                    Log.d(TAG, "onClick: url is ${span.source}")
                }
            }, start, end, flags)
        }
    }
}


  • 转到build.gradle(Module:app)文件并添加以下依赖项。

步骤3:使用activity_main.xml文件

在以下activity_main.xml文件中,我们添加了以下小部件:

  • 用户将在其中输入HTML文本的EditText,
  • 触发事件以显示HTML文本的按钮,
  • ScrollView可以平滑滚动,
  • TextView在处理输入后显示HTML。

activity_main.xml



  
  
    
    
  
    
    

输出界面:

第4步:创建Kotlin类ImageGetter.kt

创建一个类,将下载img中包含的图像 标签。以下是完整的ImageGetter.kt文件。通过参考代码中的相应注释来理解完整的代码。

ImageGetter.kt

import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.text.Html
import android.widget.TextView
import com.squareup.picasso.Picasso
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
  
// Class to download Images which extends [Html.ImageGetter]
class ImageGetter(
    private val res: Resources,
    private val htmlTextView: TextView
) : Html.ImageGetter {
  
    // Function needs to overridden when extending [Html.ImageGetter] ,
    // which will download the image
    override fun getDrawable(url: String): Drawable {
        val holder = BitmapDrawablePlaceHolder(res, null)
  
        // Coroutine Scope to download image in Background
        GlobalScope.launch(Dispatchers.IO) {
            runCatching {
  
                // downloading image in bitmap format using [Picasso] Library
                val bitmap = Picasso.get().load(url).get()
                val drawable = BitmapDrawable(res, bitmap)
  
                // To make sure Images don't go out of screen , Setting width less
                // than screen width, You can change image size if you want
                val width = getScreenWidth() - 150
  
                // Images may stretch out if you will only resize width,
                // hence resize height to according to aspect ratio
                val aspectRatio: Float =
                    (drawable.intrinsicWidth.toFloat()) / (drawable.intrinsicHeight.toFloat())
                val height = width / aspectRatio
                drawable.setBounds(10, 20, width, height.toInt())
                holder.setDrawable(drawable)
                holder.setBounds(10, 20, width, height.toInt())
                withContext(Dispatchers.Main) {
                    htmlTextView.text = htmlTextView.text
                }
            }
        }
        return holder
    }
  
    // Actually Putting images
    internal class BitmapDrawablePlaceHolder(res: Resources, bitmap: Bitmap?) :
        BitmapDrawable(res, bitmap) {
        private var drawable: Drawable? = null
  
        override fun draw(canvas: Canvas) {
            drawable?.run { draw(canvas) }
        }
  
        fun setDrawable(drawable: Drawable) {
            this.drawable = drawable
        }
    }
  
    // Function to get screenWidth used above
    fun getScreenWidth() =
        Resources.getSystem().displayMetrics.widthPixels
}

步骤5:使用MainActivity.kt文件

  • onCreate()方法内的按钮创建一个click-Listener。

MainActivity.kt

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
  
        // Click Listener to listner button click events.
        // display_html is button id from activity_main.xml 
        // You don't need to get reference to it because koltin 
        // provides synthetic import and 
        // We are gonna use for the same for rest of Views
        display_html.setOnClickListener {
            if (editor.text.isNotEmpty()) {
                displayHtml(editor.text.toString())
            }
        }
    }
}
  • 创建一个函数displayHtml() ,您刚刚在点击监听器中调用了该函数。

科特林

private fun displayHtml(html: String) {
    
      // Creating object of ImageGetter class you just created
      val imageGetter = ImageGetter(resources, html_viewer)
       
      // Using Html framework to parse html
      val styledText=HtmlCompat.fromHtml(html, 
                                         HtmlCompat.FROM_HTML_MODE_LEGACY,
                                         imageGetter,null)
         
      // to enable image/link clicking
      html_viewer.movementMethod = LinkMovementMethod.getInstance()
        
      // setting the text after formatting html and downloadig and setting images
      html_viewer.text = styledText
  }
  • 因此,现在完成了映像工作,现在应该加载映像了。以下是MainActivity.kt文件的完整代码。

科特林

import android.os.Bundle
import android.text.method.LinkMovementMethod
import androidx.appcompat.app.AppCompatActivity
import androidx.core.text.HtmlCompat
import kotlinx.android.synthetic.main.activity_main.*
  
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
  
        // Click Listener to listner button click events.
        // display_html is button id from activity_main.xml 
        // You don't need to get reference to it 
        // because koltin provides synthetic import and 
        // We are gonna use for the same for rest of Views
        display_html.setOnClickListener {
            if (editor.text.isNotEmpty()) {
                displayHtml(editor.text.toString())
            }
        }
    }
  
    private fun displayHtml(html: String) {
        // Creating object of ImageGetter class you just created
        val imageGetter = ImageGetter(resources, html_viewer)
  
        // Using Html framework to parse html
        val styledText =
            HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY, imageGetter,null)
  
        // to enable image/link clicking
        html_viewer.movementMethod = LinkMovementMethod.getInstance()
  
        // setting the text after formatting html and downloadig and setting images
        html_viewer.text = styledText
    }
}
  • 让我们看看它现在如何工作。使用其他网页的HTML。在这里,我们使用了GFG文章的以下网页。从此处获取HTML字符串文件。

输出

输出画面

图像现在正在加载,但是您可以看到,在blockquote部分中,有一条普通的难看的蓝线。现在,我们将解决此问题。

第6步:创建Kotlin类QuoteSpanClass.kt

创建一个名为QuoteSpanClass的Kotlin类,并将以下代码添加到该文件中。

QuoteSpanClass.kt

import android.graphics.Canvas
import android.graphics.Paint
import android.text.Layout
import android.text.style.LeadingMarginSpan
import android.text.style.LineBackgroundSpan
  
class QuoteSpanClass(
    private val backgroundColor: Int,
    private val stripeColor: Int,
    private val stripeWidth: Float,
    private val gap: Float
) : LeadingMarginSpan, LineBackgroundSpan {
      
    // Margin for the block quote tag
    override fun getLeadingMargin(first: Boolean): Int {
        return (stripeWidth + gap).toInt()
    }
  
    // this function draws the margin.
    override fun drawLeadingMargin(
        c: Canvas,
        p: Paint,
        x: Int,
        dir: Int,
        top: Int,
        baseline: Int,
        bottom: Int,
        text: CharSequence,
        start: Int,
        end: Int,
        first: Boolean,
        layout: Layout
    ) {
  
        val style = p.style
        val paintColor = p.color
        p.style = Paint.Style.FILL
        p.color = stripeColor
  
        // Creating margin according to color and stripewidth it recieves
        // Press CTRL+Q on function name to read more
        c.drawRect(x.toFloat(), top.toFloat(), x + dir * stripeWidth, bottom.toFloat(), p)
        p.style = style
        p.color = paintColor
    }
  
    override fun drawBackground(
        c: Canvas,
        p: Paint,
        left: Int,
        right: Int,
        top: Int,
        baseline: Int,
        bottom: Int,
        text: CharSequence,
        start: Int,
        end: Int,
        lnum: Int
    ) {
        val paintColor = p.color
        p.color = backgroundColor
  
        // It draws the background on which blockquote text is written
        c.drawRect(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat(), p)
        p.color = paintColor
    }
}

步骤7:使用MainActivity.kt文件

  • 由于创建了QuoteSpanClass,是时候在MainActivity.kt中使用此类了但是在您需要创建一个函数来解析blockquote标签并使用QuoteSpanClass绘制边距和背景之前,该是时候了。

MainActivity.kt

private fun replaceQuoteSpans(spannable: Spannable) 
{
  val quoteSpans: Array = 
      spannable.getSpans(0, spannable.length - 1, QuoteSpan::class.java)
  
  for (quoteSpan in quoteSpans) 
  {
    val start: Int = spannable.getSpanStart(quoteSpan)
    val end: Int = spannable.getSpanEnd(quoteSpan)
    val flags: Int = spannable.getSpanFlags(quoteSpan)
    spannable.removeSpan(quoteSpan)
       spannable.setSpan(
               QuoteSpanClass(
                    // background color
                    ContextCompat.getColor(this, R.color.colorPrimary),  
                    // strip color
                    ContextCompat.getColor(this, R.color.colorAccent),
                    // strip width
                    10F, 50F
                ),
                start, end, flags
            )
        }   
  }
  • 最后,在设置html_viewer的文本之前,请从displayHtml()函数调用此函数以下是MainActivity.kt文件的完整代码。

科特林

import android.os.Bundle
import android.text.Spannable
import android.text.method.LinkMovementMethod
import android.text.style.QuoteSpan
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.text.HtmlCompat
import kotlinx.android.synthetic.main.activity_main.*
  
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
  
        // Click Listener to listner button click events.
        // display_html is button id from activity_main.xml 
        // You don't need to get reference to it
        // because koltin provides synthetic import and
        // We are gonna use for the same for rest of Views
        display_html.setOnClickListener {
            if (editor.text.isNotEmpty()) {
                displayHtml(editor.text.toString())
            }
        }
    }
  
    private fun displayHtml(html: String) {
        // Creating object of ImageGetter class you just created
        val imageGetter = ImageGetter(resources, html_viewer)
  
        // Using Html framework to parse html
        val styledText =
            HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY, imageGetter,null)
  
        replaceQuoteSpans(styledText as Spannable)
  
        // setting the text after formatting html and downloadig and setting images
        html_viewer.text = styledText
  
        // to enable image/link clicking
        html_viewer.movementMethod = LinkMovementMethod.getInstance()
  
    }
  
    private fun replaceQuoteSpans(spannable: Spannable)
    {
        val quoteSpans: Array =
            spannable.getSpans(0, spannable.length - 1, QuoteSpan::class.java)
  
        for (quoteSpan in quoteSpans)
        {
            val start: Int = spannable.getSpanStart(quoteSpan)
            val end: Int = spannable.getSpanEnd(quoteSpan)
            val flags: Int = spannable.getSpanFlags(quoteSpan)
            spannable.removeSpan(quoteSpan)
            spannable.setSpan(
                QuoteSpanClass(
                    // background color
                    ContextCompat.getColor(this, R.color.colorPrimary),
                    // strip color
                    ContextCompat.getColor(this, R.color.colorAccent),
                    // strip width
                    10F, 50F
                ),
                start, end, flags
            )
        }
    }
}

输出

现在,让我们在输出屏幕中查看更改。

输出画面

步骤8:在MainActivity.kt文件中创建ImageImage()方法

  • 但是仍然存在一个问题。如果单击图像怎么办?到目前为止,什么都没有发生。您需要添加几行来处理。

科特林

// Function to parse image tags and enable click events
fun ImageClick(html: Spannable) 
{
  for (span in html.getSpans(0, html.length, ImageSpan::class.java))
  {
    val flags = html.getSpanFlags(span)
    val start = html.getSpanStart(span)
    val end = html.getSpanEnd(span)
    html.setSpan(object : URLSpan(span.source) {
         override fun onClick(v: View) {
                Log.d(TAG, "onClick: url is ${span.source}")
            }
  }, start, end, flags)
}
  • 然后在设置html_viewer的文本之前,从displayHtml()函数调用此函数以下是MainActivity.kt文件的完整代码。

科特林

import android.os.Bundle
import android.text.Spannable
import android.text.method.LinkMovementMethod
import android.text.style.ImageSpan
import android.text.style.QuoteSpan
import android.text.style.URLSpan
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.text.HtmlCompat
import kotlinx.android.synthetic.main.activity_main.*
  
private const val TAG="MainActivity"
  
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
  
        // Click Listener to listner button click events.
        // display_html is button id from activity_main.xml 
        // You don't need to get reference to it
        // because koltin provides synthetic import and
        // We are gonna use for the same for rest of Views
        display_html.setOnClickListener {
            if (editor.text.isNotEmpty()) {
                displayHtml(editor.text.toString())
            }
        }
    }
  
    private fun displayHtml(html: String) {
        // Creating object of ImageGetter class you just created
        val imageGetter = ImageGetter(resources, html_viewer)
  
        // Using Html framework to parse html
        val styledText =
            HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY, imageGetter, null)
  
        replaceQuoteSpans(styledText as Spannable)
        ImageClick(styledText as Spannable)
  
        // setting the text after formatting html and downloadig and setting images
        html_viewer.text = styledText
  
        // to enable image/link clicking
        html_viewer.movementMethod = LinkMovementMethod.getInstance()
  
    }
  
    private fun replaceQuoteSpans(spannable: Spannable) {
        val quoteSpans: Array =
            spannable.getSpans(0, spannable.length - 1, QuoteSpan::class.java)
  
        for (quoteSpan in quoteSpans) {
            val start: Int = spannable.getSpanStart(quoteSpan)
            val end: Int = spannable.getSpanEnd(quoteSpan)
            val flags: Int = spannable.getSpanFlags(quoteSpan)
            spannable.removeSpan(quoteSpan)
            spannable.setSpan(
                QuoteSpanClass(
                    // background color
                    ContextCompat.getColor(this, R.color.colorPrimary),
                    // strip color
                    ContextCompat.getColor(this, R.color.colorAccent),
                    // strip width
                    10F, 50F
                ),
                start, end, flags
            )
        }
    }
  
    // Function to parse image tags and enable click events
    fun ImageClick(html: Spannable) {
        for (span in html.getSpans(0, html.length, ImageSpan::class.java)) {
            val flags = html.getSpanFlags(span)
            val start = html.getSpanStart(span)
            val end = html.getSpanEnd(span)
            html.setSpan(object : URLSpan(span.source) {
                override fun onClick(v: View) {
                    Log.d(TAG, "onClick: url is ${span.source}")
                }
            }, start, end, flags)
        }
    }
}
  • 现在,如果您单击任何图像并选中Logcat,您将看到正在记录图像的URL。从那里您可以使用该URL触发某些函数。

输出:在模拟器上运行

资源:在此处获取完整的项目文件。

想要一个节奏更快,更具竞争性的环境来学习Android的基础知识吗?
单击此处,前往由我们的专家精心策划的指南,以使您立即做好行业准备!