Android实现一个可折叠的TextView

前言

下左是UI给的效果图,最初准备用Manabu-GT/ExpandableTextView去实现,如下第二、三张图效果尚可,但是跟实际UI略有出入:

  1. 折叠后的最后一行没有省略号。
  2. 折叠箭头在文本最下面,而不是在最后一行的最右边。
    为了解决这个问题,就只能自己动手撸一个。
    在这里插入图片描述在这里插入图片描述在这里插入图片描述

效果图

话不多说,上效果图。跟UI设计图 基本完全一致。

在这里插入图片描述在这里插入图片描述

实现思路

  1. 首先需要计算文本在TextView完全显示的最大行数。
  2. 然后需要获取文本在TextView中第n行的内容,并且可以设置初始显示行数m。
  3. 看下图。

在这里插入图片描述

核心代码

计算行数
/**
     * 计算行数
     */
    private fun initLines() {
        //将文本内容全部给tvFirst,方便后面计算行数,获取每行的文本内容
        tvFirst.text = text
        tvFirst.post {
            //绘制时获取tvFirst实际总行数,直接获取返回的是0
            maxLines = tvFirst.lineCount
            //最大行数小于等于要显示的行数
            if (maxLines <= showLines) {
                //tvSecond隐藏,只显示tvFirst
                tvSecond.visibility = View.GONE
                tvFirst.setLines(tvFirst.lineCount)
            } else {
                tvSecond.visibility = View.VISIBLE
                //获取tvFirst显示布局,可根据改布局获取文本中每行的开始位置和结束位置
                val layout = tvFirst.layout
                if (isExpand) {//展开
                    //获取展开最后一行的内容,展开时给tvSecond显示
                    lastLineStr = text.substring(layout.getLineStart(maxLines - 1), layout.getLineEnd(maxLines - 1))
                    //设置tvFirst的行数=最大行数-1
                    tvFirst.setLines(maxLines - 1)
                    //设置tvSecond的行数控制其显示内容,此处设置为maxLines=2是因为可能存在:
                    //最后一行的内容刚好完全填满,而tvSecond由于右边drawableRight和drawablePadding的存在所以可能显示不全,只能加多一行显示。
                    tvSecond.maxLines = 2
                    tvSecond.text = lastLineStr
                } else {
                    //设置tvFirst的行数=折叠时显示的行数-1
                    tvFirst.setLines(showLines - 1)
                    val start = layout.getLineStart(showLines - 1)
                    val end = layout.getLineEnd(showLines - 1)
                    secondTextLineStr = text.substring(start, end)
                    //获取折叠时最后一行的内容,给tvSecond显示
                    tvSecond.maxLines = 1
                    tvSecond.text = secondTextLineStr
                }
            }
        }

    }
处理列表展开错乱的情况
/**
     * 在列表中使用赋值文本请使用此方法
     * 用SparseBooleanArray记录列表中展开的位置,防止错乱
     */
    fun setText(string: String, collapsedStatus: SparseBooleanArray, position: Int) {
        mCollapsedStatus = collapsedStatus
        mPosition = position
        val isCollapsed = collapsedStatus[position, false]
        this.setText(string, isCollapsed)
    }

使用

XML
<com.demon.expandablelibrary.ExpandableTextView
        android:id="@+id/expandTextView2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:padding="30dp"
        app:isExpand="true"
        app:showLines="4"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/expandTextView1"
        app:textColor="@color/colorPrimary"
        app:textSize="15sp" />
基本赋值
  expandTextView.setText("新西兰总理杰辛达阿德恩(Jacinda Ardern)表示,新西兰的华人社区
  是新西兰历史最悠久、规模最大的社区之一。")
在列表中使用
class Adapter(val context: Context) : RecyclerView.Adapter<Adapter.Holder>() {
        private val mCollapsedStatus: SparseBooleanArray = SparseBooleanArray()

        class Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
            val expandText = itemView.findViewById<ExpandableTextView>(R.id.expandText)
            val tvNo = itemView.findViewById<TextView>(R.id.tvNo)
        }

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
            val view = LayoutInflater.from(parent.context).inflate(R.layout.list, parent, false)
            return Holder(view)
        }

        override fun onBindViewHolder(holder: Holder, position: Int) {
            holder.run {
                tvNo.text = "$position"
                expandText.setText(context.getString(R.string.long_text), mCollapsedStatus, position)
            }
        }

        override fun getItemCount(): Int = 20
    }

自定义属性

属性说明
text文本内容
textColor字体颜色
textSize字体大小
expandDrawable向下展开时的图标
collapseDrawable向上折叠时的图标
showLines折叠时显示的文本行数,默认3
isExpand初始是否展开,默认false

更多

Demo和源码请看:
GitHub:https://github.com/DeMonLiu623/ExpandableTextView

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值