需求: TextView 多行文本可以設置行高(如20dp),每行文本垂直居中。
效果如下:
實現思路:通過設置 TextView 的 lineSpacingExtra
和 lineSpacingMultiplier
來實現。
lineSpacingMultiplier
的值爲行間距的倍數,默認值爲 1.0f。lineSpacingExtra
值爲具體的行間距值,如20dp。- 垂直居中靠設置 paddingTop 和 paddingBottom
TextView 相關
TextView 內部除了繼承自 View 的相關屬性和 measure、layout、draw
步驟,還包括:
- Layout: TextView 的文字排版、折行策略以及文本繪製都是在 Layout 裏面完成的,TextView 的自身測量也受 Layout 的影響。Layout 是 TextView 執行setText方法後,由 TextView 內部創建的實例,並不能由外部提供。Layout有三個子類,BoringLayout、DynamicLayout、StaticLayout。
- TransformationMethod: 用來處理最終的顯示結果的類,例如顯示密碼的時候把密碼轉換成圓點。這個類並不直接影響 TextView 內部儲存的 Text ,隻影響顯示的結果。
- MovementMethod: 用來處理 TextView 內部事件響應的類,可以針 對TextView 內文本的某一個區域做軟鍵盤輸入或者觸摸事件的響應。
- Drawables: TextView 的靜態內部類,用來處理和儲存 TextView 的 CompoundDrawables ,包括 TextView 的上下左右的 Drawable 以及錯誤提示的 Drawable。
- Spans: Spans 並不是特定的某一個類或者實現了某一個接口的類。它可以是任意類型,Spans實際上做的事情是在 TextView 的內部的 text 的某一個區域做標記。其中有部 分Spans 可以影響TextView的繪製和測量,如 ImageSpan、BackgroundColorSpan、AbsoluteSizeSpan。還有可以響應點擊事件的ClickableSpan。
- Editor: TextView作爲可編輯文本控件的時候(EditText),使用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);
}
}
參考鏈接:
文章來自: http://hanks.xyz