Android自定义View-图文混排

梳理了一下自定义View文字排版知识,实现文字环绕图片的效果

#知识点#

  • paint.breakText(CharSequence text, int start, int end, boolean measureForwards, float maxWidth, float[] measuredWidth)方法,用来测量当前View一行最多显示多少个字符
  • BitmapFactory如何以最小的内存损耗加载所需要的图片资源。因为如果将一张1000*1000像素的图片显示到100*100的View上,如果不做优化,那么将存在内存的严重浪费

效果图:

代码实现:

package com.ztw.mvvm.view

import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.util.AttributeSet
import android.util.Log
import android.view.View
import com.ztw.mvvm.R

class ImageTextView : View {
    constructor(context: Context?) : super(context)
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    )

    constructor(
        context: Context?,
        attrs: AttributeSet?,
        defStyleAttr: Int,
        defStyleRes: Int
    ) : super(context, attrs, defStyleAttr, defStyleRes)

    private val paint = Paint().apply {
        isAntiAlias = true
        style = Paint.Style.FILL
        textSize = 32f
        color = Color.BLACK
    }
    private val txt =
        "这个方法⼀一般前两个参数都填 0,第三个参数为负值。由于这个值的单位是硬编码写死的,因此像素 密度越⾼高的⼿手机,相当于 Camera 距离 View 越近,所以最好把这个值写成与机器器的 density 成正⽐比 的⼀一个负值,例例如 -6 * density。这个⽅方法⼀一般前两个参数都填 0,第三个参数为负值。由于这个值的单位是硬编码写死的,因此像素 密度越⾼高的⼿手机,相当于 Camera 距离 View 越近,所以最好把这个值写成与机器器的 density 成正⽐比 的⼀一个负值,例例如 -6 * density。这个方法⼀一般前两个参数都填 0,第三个参数为负值。由于这个值的单位是硬编码写死的,因此像素 密度越⾼高的⼿手机,相当于 Camera 距离 View 越近,所以最好把这个值写成与机器器的 density 成正⽐比 的⼀一个负值,例例如 -6 * density。这个⽅方法⼀一般前两个参数都填 0,第三个参数为负值。由于这个值的单位是硬编码写死的,因此像素 密度越⾼高的⼿手机,相当于 Camera 距离 View 越近,所以最好把这个值写成与机器器的 density 成正⽐比 的⼀一个负值,例例如 -6 * density。"

    private val array = floatArrayOf()
    private var offset = 0
    private var lineLength = 0
    private var lines = 1
    private var lineHeight = 100
    private var padding = 20f
    private val bmpWidth = 400
    private var bitmap: Bitmap? = createBmp(bmpWidth)
    private val bitmapTop: Int
    private val bitmapBottom: Int
    private val bound = Rect()

    init {
        paint.getTextBounds(txt, 0, txt.length, bound)
        bitmapTop = 50 + padding.toInt()
        bitmapBottom = (bitmapTop + (bitmap?.height ?: 0))
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        bitmap?.also {
            canvas.drawBitmap(it, padding, bitmapTop.toFloat(), paint)
        }

        do {
            Log.d(null, "lineHeight = $lineHeight")
            offset += lineLength

            val totalHeight = lines * bound.height() + padding.toInt()
            if (totalHeight in bitmapTop..bitmapBottom && bitmap != null) {
                lineLength = paint.breakText(
                    txt,
                    offset,
                    txt.length,
                    true,
                    width.toFloat() - bitmap!!.width - padding * 2,
                    array
                )
                canvas.drawText(
                    txt,
                    offset,
                    offset + lineLength,
                    padding + bmpWidth,
                    padding + lines * paint.fontSpacing,
                    paint
                )

            } else {
                lineLength = paint.breakText(
                    txt,
                    offset,
                    txt.length,
                    true,
                    width.toFloat() - padding * 2,
                    array
                )
                canvas.drawText(
                    txt,
                    offset,
                    offset + lineLength,
                    padding,
                    padding + lines * paint.fontSpacing,
                    paint
                )
            }

            lines++
        } while (offset < txt.length)


    }

    private fun createBmp(height: Int): Bitmap? {
        return try {
            BitmapFactory.Options().apply {
                inJustDecodeBounds = true //指计算图片的轮廓
            }.let {
                BitmapFactory.decodeResource(resources, R.drawable.img, it)
                it.inJustDecodeBounds = false
                //加载图片时,将原始图片按照比例压缩
                it.inDensity = it.outHeight
                it.inTargetDensity = height
                BitmapFactory.decodeResource(resources, R.drawable.img, it)
            }
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android Studio中的图文混排可以通过使用TextView和SpannableString来实现。SpannableString是一个可以设置不同样式的字符串类,可以用来设置文字的颜色、大小、字体等属性。 以下是一个简单的例子,展示如何在TextView中实现图文混排: 1. 在布局文件中添加一个TextView: ``` <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" /> ``` 2. 在Java代码中获取TextView并设置SpannableString: ``` TextView textView = findViewById(R.id.textView); // 创建一个SpannableString对象 SpannableString spannableString = new SpannableString("这是一段文字和图片混排的例子"); // 创建一个ImageSpan对象,用来设置图片 Drawable drawable = getResources().getDrawable(R.drawable.ic_launcher); drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); ImageSpan imageSpan = new ImageSpan(drawable); // 将图片插入到SpannableString中 spannableString.setSpan(imageSpan, 6, 7, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // 设置TextView的文本 textView.setText(spannableString); ``` 在上面的代码中,我们首先创建了一个SpannableString对象,然后创建了一个ImageSpan对象,用来设置图片。接着,我们将图片插入到SpannableString中,并设置了图片的位置。最后,我们将SpannableString设置为TextView的文本。 这样,就可以在TextView中实现图文混排了。当然,这只是一个简单的例子,实际上可以通过SpannableString来实现更复杂的图文混排效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值