UI效果

自定义换行右下角带标志TextView

2022-09-14  本文已影响0人  azu_test
image.png

自定义属性

    <declare-styleable name="Details">
        <attr name="line_width" format="dimension" />
        <attr name="detail_width" format="dimension" />
        <attr name="detail_color" format="color" />
        <attr name="detail_text" format="string" />
        <attr name="detail_image" format="reference|color" />
        <attr name="detail_image_size" format="dimension" />

代码实现

package com.azu.test

import android.content.Context
import android.graphics.drawable.Drawable
import android.text.*
import android.text.style.DynamicDrawableSpan
import android.text.style.ForegroundColorSpan
import android.text.style.ImageSpan
import android.util.AttributeSet
import java.lang.reflect.Method

/**
 * @author zau
 * @data 2022/09/13
 * */
class DetailsTextView : androidx.appcompat.widget.AppCompatTextView {
    private var mLineWidth = 0f
    private var mDetailWidth = 0f
    private var mDetailColor = 0
    private lateinit var mDetailText: String
    private lateinit var mDetailImage: Drawable
    private var mDetailImageSize = 0f

    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.Details)
        mLineWidth = typedArray.getDimension(R.styleable.Details_line_width, 0f)
        mDetailWidth = typedArray.getDimension(R.styleable.Details_detail_width, 0f)
        mDetailColor =
            typedArray.getColor(R.styleable.Details_detail_color, getContext().getColor(R.color.black))
        mDetailText = typedArray.getString(R.styleable.Details_detail_text).toString()
        mDetailImage = typedArray.getDrawable(R.styleable.Details_detail_image)!!
        mDetailImageSize = typedArray.getDimension(R.styleable.Details_detail_image_size, 0f)
    }

    fun setProfileIntro(originText: String?) {
        if (originText.isNullOrEmpty()) return

        var currentLength: Int = 0
        val showText = StringBuffer()
        for (i in 1..maxLines) {
            val currentLineStr = ellipsize(originText.substring(currentLength, originText.length), mLineWidth, "")
            if ((currentLength + currentLineStr.length) == originText.length) {
                text = originText
                return
            }
            //已经为最后一行,且内容显示不全,需要重新获取最后一行的内容
            if (i == maxLines && (currentLength + currentLineStr.length) < originText.length) {
                val lastLineStr = ellipsize(
                    originText.substring(currentLength, originText.length),
                    mLineWidth - mDetailWidth,
                    "\u2026"
                )
                showText.append(lastLineStr).append("${mDetailText}+")
                val span = SpannableString(showText)
                span.setSpan(
                    ForegroundColorSpan(mDetailColor),
                    currentLength + lastLineStr.length + maxLines - 1,
                    showText.length,
                    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
                )
                mDetailImage.setBounds(0, 0, mDetailImageSize.toInt(), mDetailImageSize.toInt())
                val imageSpan = ImageSpan(mDetailImage, DynamicDrawableSpan.ALIGN_CENTER)
                span.setSpan(imageSpan, showText.length - 1, showText.length, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
                text = span
                setOnClickListener {
                    //fixme 做显示更多的操作
                }
            } else {
                //处理第二行首个字符为特殊字符时会把第一行的最后一个字符移动到第二行的异常问题
                showText.append("${currentLineStr}\n")
                currentLength += currentLineStr.length
            }
        }
    }


    private fun ellipsize(originText: String, width: Float, ellipsis: String): CharSequence {
        val cls: Class<*> = TextUtils::class.java
        val method: Method =
            cls.getMethod(
                "ellipsize",
                CharSequence::class.java,
                TextPaint::class.java,
                Float::class.javaPrimitiveType,
                TextUtils.TruncateAt::class.java,
                Boolean::class.javaPrimitiveType,
                TextUtils.EllipsizeCallback::class.java,
                TextDirectionHeuristic::class.java,
                String::class.java
            )
        method.isAccessible = true
        val firstLineStr = method.invoke(
            null, originText, paint,
            width,
            TextUtils.TruncateAt.END,
            false,
            null,
            TextDirectionHeuristics.FIRSTSTRONG_LTR,
            ellipsis
        )
        return firstLineStr as CharSequence
    }
}

布局使用

            <com.azu.test.DetailsTextView
                android:id="@+id/tv_intro"
                android:layout_width="260px"
                android:layout_height="wrap_content"
                android:layout_marginTop="16px"
                android:ellipsize="end"
                android:lineHeight="32px"
                android:lineSpacingExtra="0px"
                android:maxLines="2"
                android:textColor="#99FFFFFF"
                android:textSize="20px"
                app:detail_color="#46A78B"
                app:detail_image="@drawable/ic_arrow"
                app:detail_image_size="20px"
                app:detail_text="详情"
                app:detail_width="66px"
                app:line_width="260px" />

代码设置显示内容

binding.tvIntro.setProfileIntro("azu")
上一篇 下一篇

猜你喜欢

热点阅读