小菜最近調整一個小需求,為了整體顯示效果,需要限制一部分文字的長度,超過部分以...代替。
小菜本想偷個懶,用 android:maxLength="6" 屬性配合 android:maxLines="1" 以及 android:ellipsize="end" 來實作,但是隻可限制字元床度為6,沒有省略号。然後想起有一個 android:maxEms="6" 屬性來實作,預設超過長度以省略号結束。結果發現并非按字元長度計算,小菜還是太天真了。
android:maxEms="6"
Tips1: android:singleLine="true" 屬性已經在 API 中不建議使用,小菜在現有的裝置中測試與 android:maxLines="1" 屬性效果完全一緻。
Tips2: 在使用 android:maxEms="6" 屬性時, TextView 的寬度需為 wrap_content 方式。
以下是小菜測試時遇到的問題:
左側是從 maxEms = “1” 開始遞增到 “16”,右側是測量文字所占的寬度:
純漢字
純字母
純數字
測試發現:
- 無論是文字還是字母或是數字,設定完 maxEms 之後,文字所占的寬度是一緻的,随着 maxEms 的遞增,文字的寬度也是相同幅度遞增的;
- 不管是文字還是字母或數字,都不是單純的按照字元個數來展示的,而是所占螢幕的寬度,是以并不是網上一些朋友說的顯示内容為 maxEms - 1 +”...“。
- 若限制字元串長度請嘗試 maxLength,若字号不變,限制文字所在螢幕寬度,可嘗試 maxEms。
TextView 源碼中 maxEms
/**
* Makes the TextView at most this many ems wide
*
* @attr ref android.R.styleable#TextView_maxEms
*/
@android.view.RemotableViewMethod
public void setMaxEms(int maxems) {
mMaxWidth = maxems;
mMaxWidthMode = EMS;
requestLayout();
invalidate();
}
/**
* @return the maximum width of the TextView, expressed in ems or -1 if the maximum width
* was set in pixels instead (using {@link #setMaxWidth(int)} or {@link #setWidth(int)}).
* 文本視圖的最大寬度,以EMS表示,或如果寬度為1,則表示最大寬度
* 設定為像素(使用{@ Link LyStMax寬度(int)}或{@ Link LyStSuffelt(int)})
* @see #setMaxEms(int)
* @see #setEms(int)
*
* @attr ref android.R.styleable#TextView_maxEms
*/
public int getMaxEms() {
return mMaxWidthMode == EMS ? mMaxWidth : -1;
}
小菜查閱相關資料以及自己的了解是:
- em 是字型寬度的排版機關,16 點字型中的一個是 16 分;
- em 和 ex 單元取決于字型,并且對于文檔中的每個元素可能不同。em 隻是字型大小。在具有 2in 字型的元素中,1em 是以意味着 2in。在 em 中表示大小,例如邊距和填充,意味着它們與字型大小有關,并且如果使用者有大字型(例如,在大螢幕上)或小字型(例如,在手持裝置上),大小将成比例。
- 它是字母 M 在給定的英語字型大小中的寬度。是以 2em 是這個字型中字母 M 的兩倍。字型不同于英語,它是這個字型中最寬的字母寬度,這個寬度是不同的像素大小,然後是英語字型中的 M 的寬度大小,但是它仍然是 1EM。是以如果我用 12sp 的英文字型使用文本,1M 相對于這個 12sp 的英語字型,用意大利字型加上1。
測試主要代碼:
// xml 中 TextView
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxEms="6"
android:maxLines="1"
android:text="@string/test_str1" />
// Kotlin 擷取文字寬度
fun getTextViewWidth(tv: TextView): String {
val spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
tv.measure(spec, spec)
val measuredWidthTicketNum = tv.getMeasuredWidth()
return measuredWidthTicketNum.toString()
}
下面是小菜的公衆号,歡迎閑來吐槽~
小菜公衆号