需求: TextView 多行文本可以设置行高(如20dp),每行文本垂直居中。
效果如下:
实现思路:通过设置 TextView 的 lineSpacingExtra
和 lineSpacingMultiplier
来实现。
lineSpacingMultiplier
的值为行间距的倍数,默认值为 1.0f。 lineSpacingExtra
值为具体的行间距值,如20dp。 TextView 内部除了继承自 View 的相关属性和 measure、layout、draw
步骤,还包括:
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);
}
}
参考链接:
TextView源码解析
用TextPaint来绘制文字
文章来自:http://hanks.xyz