ScrollView中自定义View不显示

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>

ScrollView中自定义View不显示

然后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);
    }

上一篇:ScrollView高度不能充满全屏


下一篇:scrollview 加百度地图 手势冲突解决办法