public class TextCustomView extends View {
public TextCustomView(Context context) {
super(context);
init(context);
}
public TextCustomView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
private Paint paint;
private void init(Context context) {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.parseColor("#00008a"));
paint.setTextSize(BaseUtils.dip2px(context, 16));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.parseColor("#ffebcc"));//来个背景色方便看控件大小
String txt="换行必须用StaticLayout,drawText只显示一行,不信你看";
canvas.drawText(txt,10,400,paint);
}
}
放在LinearLayout中,显示没问题。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="vertical"
tools:context=".InputActivity">
<com.lagou.test.view.input.TextCustomView
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
然后LinearLayout换成ScrollView之后 不显示了。
重写noMeasure方法:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
if (MeasureSpec.UNSPECIFIED == heightMode) {
int heightSize = (int) (widthSize * 1.2f);
setMeasuredDimension(widthMeasureSpec, heightSize);
}
}
这样就可以重新显示了。
原因是ScrollView的onMeasure并未处理MeasureSpec.UNSPECIFIED。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (!mFillViewport) {
return;
}
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (heightMode == MeasureSpec.UNSPECIFIED) {
return;
}
.......
.......
}
父布局遇到MeasureSpec.UNSPECIFIED 直接return,导致子控件默认的测量方式得出的高度就是 初始值 0,所以不显示。此时需要子控件自己处理该case。
上面重写onMeasure可以优化为这样:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int reHeight = resolveSize(heightSize, heightMeasureSpec);
setMeasuredDimension(widthMeasureSpec, reHeight);
}
}
resolveSize源码处理了 case MeasureSpec.UNSPECIFIED:
,源码如下
public static int resolveSize(int size, int measureSpec) {
return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK;
}
public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {
final int specMode = MeasureSpec.getMode(measureSpec);
final int specSize = MeasureSpec.getSize(measureSpec);
final int result;
switch (specMode) {
case MeasureSpec.AT_MOST:
if (specSize < size) {
result = specSize | MEASURED_STATE_TOO_SMALL;
} else {
result = size;
}
break;
case MeasureSpec.EXACTLY:
result = specSize;
break;
case MeasureSpec.UNSPECIFIED:
default:
result = size;
}
return result | (childMeasuredState & MEASURED_STATE_MASK);
}