TextView 設定行高並垂直居中
阿新 • • 發佈:2019-01-06
需求: TextView 多行文字可以設定行高(如20dp),每行文字垂直居中。
效果如下:
實現思路:通過設定 TextView 的 lineSpacingExtra
和 lineSpacingMultiplier
來實現。
lineSpacingMultiplier
的值為行間距的倍數,預設值為 1.0f。lineSpacingExtra
值為具體的行間距值,如20dp。- 垂直居中靠設定 paddingTop 和 paddingBottom
TextView 相關
TextView 內部除了繼承自 View 的相關屬性和 measure、layout、draw
步驟,還包括:
- Layout
- TransformationMethod: 用來處理最終的顯示結果的類,例如顯示密碼的時候把密碼轉換成圓點。這個類並不直接影響 TextView 內部儲存的 Text ,隻影響顯示的結果。
- MovementMethod: 用來處理 TextView 內部事件響應的類,可以針 對TextView 內文字的某一個區域做軟鍵盤輸入或者觸控事件的響應。
- Drawables
- Spans: Spans 並不是特定的某一個類或者實現了某一個介面的類。它可以是任意型別,Spans實際上做的事情是在 TextView 的內部的 text 的某一個區域做標記。其中有部 分Spans 可以影響TextView的繪製和測量,如 ImageSpan、BackgroundColorSpan、AbsoluteSizeSpan。還有可以響應點選事件的ClickableSpan。
- Editor
- InputConnection: EditText 的文字輸入部分是在 TextView 中完成的。而 InputConnection 是軟鍵盤和TextView之間的橋樑,所有的軟鍵盤的輸入文字、修改文字和刪除文字都是通過 InputConnection 傳遞給 TextView 的。
TextView 預設文字的上下邊距
TextView 的 textSize
屬性代表的意義是字型的大小,體現為字型高度,一般單位是 sp, sp 代表的字型大小根據手機設定的文字大小有關,預設的 1sp = 1dp
。但是Android 系統會預設的給文字增加一點邊框。
Android 提供了一個 setIncludeFontPadding 方法.用來設定 TextView 是否在頂部和底部保留一些空隙,預設為 ture 。如果我們設定為 false 的話可能會導致某些語言顯示的不完整, 如 Arabic Kannada 。在 StaticLayout
的 setIncludePad
方法提到。
/**
* Set whether to include extra space beyond font ascent and descent (which is
* needed to avoid clipping in some languages, such as Arabic and Kannada). The
* default is {@code true}.
*
* @param includePad whether to include padding
* @return this builder, useful for chaining
* @see android.widget.TextView#setIncludeFontPadding
*/
public Builder setIncludePad(boolean includePad) {
mIncludePad = includePad;
return this;
}
通過 android:includeFontPadding="false"
可以去掉一定的邊距值但是不能完全去掉。還少達不到
文字高度精確,所以不通過過設定 lineSpacingMultiplier 來改變, lineSpacingMultiplier 為 0 , 那麼多行文字就都變成一行了。
最終結果是:
lineSpacingMultiplier = 0
lineSpacingExtra = 行高
paddingTop = paddingBottom = (行高-字型大小)* 0.5
封裝成控制元件。這裡繼承了EditText, 預設的編輯文字時的行高會改變,所以在文字變化時需要重新設定.
package xyz.hanks.note.ui.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.text.Editable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.widget.EditText;
import xyz.hanks.note.R;
/**
* 每一行的文字垂直居中
* Created by hanks on 16/7/2.
*/
public class LineTextView extends EditText {
private float ITEM_HEIGHT = 125;
boolean reLayout = false;
TextWatcher textWatcher;
public LineTextView(Context context) {
this(context,null);
}
public LineTextView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public LineTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
addTextChangedListener(new android.text.TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (textWatcher != null) {
textWatcher.beforeTextChanged(charSequence, i, i1, i2);
}
}
@Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
float add = ITEM_HEIGHT;
setLineSpacing(0f, 1f);
setLineSpacing(add, 0);
setIncludeFontPadding(false);
setGravity(Gravity.CENTER_VERTICAL);
int top = (int) ((add - getTextSize()) * 0.5f);
setPadding(getPaddingLeft(), top, getPaddingRight(), -top);
if (textWatcher != null) {
textWatcher.onTextChanged(charSequence, i, i1, i2);
}
}
@Override public void afterTextChanged(Editable editable) {
if (textWatcher != null) {
textWatcher.afterTextChanged(editable);
}
}
});
}
@Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!reLayout) {
reLayout = true;
setIncludeFontPadding(false);
setGravity(Gravity.CENTER_VERTICAL);
setLineSpacing(ITEM_HEIGHT, 0);
int top = (int) ((ITEM_HEIGHT - getTextSize()) * 0.5f);
setPadding(getPaddingLeft(), top, getPaddingRight(), -top);
requestLayout();
invalidate();
}
}
public void addTextWatcher(TextWatcher textWatcher) {
this.textWatcher = textWatcher;
}
public interface TextWatcher {
void beforeTextChanged(CharSequence var1, int var2, int var3, int var4);
void onTextChanged(CharSequence var1, int var2, int var3, int var4);
void afterTextChanged(Editable var1);
}
}
參考連結: