前言
下左是UI給的效果圖,最初準備用Manabu-GT/ExpandableTextView去實現,如下第二、三張圖效果尚可,但是跟實際UI略有出入:
- 摺疊後的最後一行沒有省略號。
- 摺疊箭頭在文本最下面,而不是在最後一行的最右邊。
爲了解決這個問題,就只能自己動手擼一個。
效果圖
話不多說,上效果圖。跟UI設計圖 基本完全一致。
實現思路
- 首先需要計算文本在TextView完全顯示的最大行數。
- 然後需要獲取文本在TextView中第n行的內容,並且可以設置初始顯示行數m。
- 看下圖。
核心代碼
計算行數
/**
* 計算行數
*/
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