剛遇到一個問題,如題,我有2個ListView嵌套,是以需要計算嵌套中的ListView高度,然後就發現,TextView 中的文字換行會導緻高度計算有誤,隻算到一行,So,上網查解決方法,找到的方法都是一個
public class myTextView extends TextView {
private Context context;
public myTextView(Context context) {
super(context);
// TODO Auto-generated constructor stub
this.context = context;
}
public myTextView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
this.context = context;
}
public myTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
this.context = context;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Layout layout = getLayout();
if (layout != null) {
int height = (int)FloatMath.ceil(getMaxLineHeight(this.getText().toString()))
+ getCompoundPaddingTop() + getCompoundPaddingBottom();
int width = getMeasuredWidth();
setMeasuredDimension(width, height);
}
}
private float getMaxLineHeight(String str) {
float height = f;
float screenW = ((Activity)context).getWindowManager().getDefaultDisplay().getWidth();
float paddingLeft = ((LinearLayout)this.getParent()).getPaddingLeft();
float paddingReft = ((LinearLayout)this.getParent()).getPaddingRight();
//這裡具體this.getPaint()要注意使用,要看你的TextView在什麼位置,這個是拿TextView父控件的Padding的,為了更準确的算出換行
int line = (int) Math.ceil( (this.getPaint().measureText(str)/(screenW-paddingLeft-paddingReft)));
height = (this.getPaint().getFontMetrics().descent-this.getPaint().getFontMetrics().ascent)*line; return height;}
}
基本找到所有資料都是以上的代碼,并不知道原作者到底是誰,自定義TextView計算高度,但是我用了之後發現有幾個問題
一、當TextView沒有占據一行時,顯示會不全,也就是TextView左邊或者右邊還有控件占據了寬度,那麼就會有部分資料不顯示
二、沒有考慮文本中含有\n換行符,計算行數有誤
三、沒有計算TextView本身的Padding
四、擷取螢幕密度方式有誤,使用以下方法強轉是有風險的,且方法已經過時
float screenW = ((Activity)context).getWindowManager().getDefaultDisplay().getWidth();
float paddingLeft =
解決辦法就是當你的TextView旁邊還有其他控件占據寬度時,把TextView的寬度定死,或使用weight,是TextView與其他View按比例配置設定寬度。
修改後的版本
public class MTextView extends TextView {
private Context context;
public MTextView(Context context) {
super(context);
// TODO Auto-generated constructor stub
this.context = context;
}
public MTextView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
this.context = context;
}
public MTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
this.context = context;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int mode = MeasureSpec.getMode(heightMeasureSpec);
Layout layout = getLayout();
if (layout != null) {
int height = (int) Math.ceil(getMaxLineHeight(this.getText().toString(), mode))
+ getCompoundPaddingTop() + getCompoundPaddingBottom();
int width = getMeasuredWidth();
setMeasuredDimension(width, height);
}
}
private float getMaxLineHeight(String str, int mode) {
float height = f;
float width = getMeasuredWidth();
float widthPixels = context.getResources().getDisplayMetrics().widthPixels;
//這裡具體this.getPaint()要注意使用,要看你的TextView在什麼位置,
// 這個是拿TextView父控件的Padding的,為了更準确的算出換行
float pLeft = ((LinearLayout) getParent()).getPaddingLeft();
float pRight = ((LinearLayout) getParent()).getPaddingRight();
//檢測字元串中是否包含換行符,獲得換行的次數,在之後計算高度時加上
int br = ;
if (str.contains("\n"))
br = str.split("\n").length - ;
/**
* wrap_content/未指定寬度(MeasureSpec.UNSPECIFIED),則用螢幕寬度計算
* 否則就使用View自身寬度計算,并且無需計算Parent的Padding
*/
int line;
if (mode == MeasureSpec.UNSPECIFIED)
line = (int)
Math.ceil((this.getPaint().measureText(str) /
(widthPixels - getPaddingLeft() - pLeft - pRight - getPaddingRight())));
else {
line = (int)
Math.ceil((this.getPaint().measureText(str) /
(width - getPaddingLeft() - getPaddingRight())));
}
height = (this.getPaint().getFontMetrics().descent -
this.getPaint().getFontMetrics().ascent) * (line + br);
return height;
}
}
如果有更好的解決辦法,或代碼中有忽略的問題,bug請留言。
另,可能有人會問RelativeLayout怎麼辦,我想說,計算ListView高度如果有RelativeLayout,那麼是計算不了的,估計隻能再次重寫RelativeLayout…