文字环绕图片效果实现

书接上回,我们来讲讲如何实现“文字环绕图片”的效果吧。整体预计实现的效果如下:

请添加图片描述

日常杂谈

我喜欢看动漫,接下来的所有博客都会和我日常生活结合在一起写,这样感觉会让自己的博客会有温度,我感觉每个人都应该有自己的爱好,动漫也是一种爱好,就和女孩喜欢看剧一样,没有什么高低贵贱之分,不是说喜欢打篮球就高人一等。不虚伪不做作,这才是我,最近在看“我推的孩子”。

正文

如果是单纯需要实现自动换行的效果,那么只需要通过StaticLayout的方式就能简单地绘制对应的文字换行效果。使用也是非常简单,我就不多赘述了。

val staticLayout =
    StaticLayout(
        textPlain, textPaint, width, Layout.Alignment.ALIGN_NORMAL,
        1f,
        textPaint.fontSpacing / 2, true
    )
staticLayout.draw(canvas)

但是如果希望实现我们上述所提及的文字环绕效果,通过上述的方式很明显是不够的,我们就需要具体情况具体分析,根据图片的位置来动态地确定文字应该绘制的位置。

首先我们来看一下大体的思路:

  1. 确定目的:我们需要在(width/2,height/4)的位置开始绘制一张图片,图片的宽度是width/2,然后图片的高度未知,因为我们需要保持图片的宽高比,总不能说,原来长方形的图片放进来之后就压缩成方形的了。

    fun getAvatar(context: Context, @DrawableRes drawableRes: Int, withInWidth: Int): Bitmap {
          
          
            val option = BitmapFactory.Options()
            option.inJustDecodeBounds = true
            BitmapFactory.decodeResource(resources, drawableRes, option)
            option.apply {
          
          
                inDensity = outWidth
                inTargetDensity = withInWidth
                inJustDecodeBounds = false
            }
            return BitmapFactory.decodeResource(resources, drawableRes, option)
        }
    
  2. 在对应的位置绘制对应的图片,并存储图片的左上角的纵坐标和左下角的纵坐标值

    val bitmap = getAvatar(context, R.drawable.avatar, width / 2)
            canvas.drawBitmap(bitmap, width/2f,height/4f, paint)
            val mipmapStartX = width / 4
            val mipmapStartY = height / 4
            val mipmapEndY = height / 4 +bitmap.height
    
  3. 逐行绘制文字,当文字绘制的纵坐标和图片的纵坐标有重合的时候,限制文字的绘制宽度

    var startIndex = 0
            val endIndex = textPlain.length
            var currentWidth = width
            var startY = -metrics.top
            var breakLen: Int = 0
            while (startIndex < endIndex) {
          
          
                val textTop = startY + metrics.top
                val textBottom = textTop + (metrics.bottom - metrics.top)
                currentWidth =
                    if (textBottom > mipmapStartY && textTop < mipmapEndY) {
          
          
                        width / 2
                    } else width
                breakLen = textPaint.breakText(
                    textPlain, startIndex, endIndex, true,
                    currentWidth.toFloat(), null
                )
    
                canvas.drawText(textPlain, startIndex, startIndex + breakLen, 0f, startY, textPaint)
                startIndex += breakLen
                startY += textPaint.fontSpacing
            }
    

    就这样,整体的环绕效果绘制就完成了。如下是完整的代码:

    /**
     * 绘制一个环绕图片的文字效果
     */
    class RoundAvatarTextView(context: Context, attrs: AttributeSet) : View(context, attrs) {
          
          
        private val paint: Paint = Paint().apply {
          
           isAntiAlias = true }
        private var metrics: Paint.FontMetrics = Paint.FontMetrics()
        private val textPaint: TextPaint = TextPaint().apply {
          
          
            textSize = 20.dp
        }
        val dstRectF = RectF(width/2f,height/4f,width.toFloat(),height/4f*3)
    
        private val textPlain = resources.getText(R.string.think)
        override fun onDraw(canvas: Canvas) {
          
          
            super.onDraw(canvas)
            textPaint.getFontMetrics(metrics)
    
            val bitmap = getAvatar(context, R.drawable.avatar, width / 2)
            canvas.drawBitmap(bitmap, width/2f,height/4f, paint)
            val mipmapStartX = width / 4
            val mipmapStartY = height / 4
            val mipmapEndY = height / 4 +bitmap.height
    
            var startIndex = 0
            val endIndex = textPlain.length
            var currentWidth = width
            var startY = -metrics.top
            var breakLen: Int = 0
            while (startIndex < endIndex) {
          
          
                val textTop = startY + metrics.top
                val textBottom = textTop + (metrics.bottom - metrics.top)
                currentWidth =
                    if (textBottom > mipmapStartY && textTop < mipmapEndY) {
          
          
                        width / 2
                    } else width
                breakLen = textPaint.breakText(
                    textPlain, startIndex, endIndex, true,
                    currentWidth.toFloat(), null
                )
    
                canvas.drawText(textPlain, startIndex, startIndex + breakLen, 0f, startY, textPaint)
                startIndex += breakLen
                startY += textPaint.fontSpacing
            }
        }
    
        fun getAvatar(context: Context, @DrawableRes drawableRes: Int, withInWidth: Int): Bitmap {
          
          
            val option = BitmapFactory.Options()
            option.inJustDecodeBounds = true
            BitmapFactory.decodeResource(resources, drawableRes, option)
            option.apply {
          
          
                inDensity = outWidth
                inTargetDensity = withInWidth
                inJustDecodeBounds = false
            }
            return BitmapFactory.decodeResource(resources, drawableRes, option)
        }
    }
    

猜你喜欢

转载自blog.csdn.net/qq_31433709/article/details/130985882