自定义视图不绘图

时间:2014-02-04 12:47:34

标签: android canvas view

我要尝试在我的自定义视图上绘制一个简单的弧,但它不会显示任何内容。很长一段时间以来一直困扰着我。

这是主要的行为:

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
  //setContentView(new Ring(this));

}}

这是主要的xml:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:ring="http://schemas.android.com/apk/res/com.shockwave.arandomer"
     xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/scrollView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:paddingBottom="@dimen/activity_vertical_margin"
     android:paddingLeft="@dimen/activity_horizontal_margin"
     android:paddingRight="@dimen/activity_horizontal_margin"
     android:paddingTop="@dimen/activity_vertical_margin">

    <LinearLayout 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical|center_horizontal|center"
        android:orientation="vertical" >

            <com.shockwave.arandomer.Ring 
                android:id="@+id/ring"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                ring:ring_color="red"
                ring:stroke_width="5.0"/>

    </LinearLayout>
</ScrollView>

然后这是绘图的主要类:

public class Ring extends ViewGroup{
Paint paint = null;
float stroke_w;
int ring_color;

public Ring(Context context,AttributeSet attrs) {
    super(context,attrs);
    setFocusable(true);



    TypedArray type = context.getTheme().obtainStyledAttributes(attrs,R.styleable.Ring,0,0);
    try{
        stroke_w = type.getFloat(R.styleable.Ring_stroke_width, (float)3.0);
        ring_color = type.getInteger(R.styleable.Ring_ring_color, 0);//default: black
    }finally{
        type.recycle();
    }

    switch(ring_color){
    case 0:
        ring_color = Color.BLACK;
        break;
    case 1:
        ring_color = Color.RED;
        break;
    case 2:
        ring_color = Color.GREEN;
        break;
    }

    Ring_main ring_view = new Ring_main(getContext());
    addView(ring_view);

    //ring_view.invalidate();
}

@Override
protected void onDraw(Canvas canvas){
    super.onDraw(canvas);

}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){

    int minw = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();
   int w = Math.max(minw, MeasureSpec.getSize(widthMeasureSpec));

   int minh = getPaddingTop() + getPaddingBottom() + getSuggestedMinimumHeight();
   int h = Math.max(MeasureSpec.getSize(heightMeasureSpec), minh);



   setMeasuredDimension(w, h);
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh){
    super.onSizeChanged(w, h, oldw, oldh);
}

private class Ring_main extends View{

    public Ring_main(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }

    public Ring_main(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
    }

    @Override
    protected void onDraw(Canvas canvas){
        super.onDraw(canvas);

        canvas.drawColor(Color.WHITE);



        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(ring_color);
        paint.setStrokeWidth(stroke_w);
        paint.setStyle(Style.STROKE);

        RectF oval = new RectF();
        oval.set(100, 100, 300, 300);
        canvas.drawArc(oval, 90, 180, false, paint);
    }
}

@Override
protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {
    // TODO Auto-generated method stub

}
}

感谢您的帮助

1 个答案:

答案 0 :(得分:0)

您的内部班级Ring_main不会覆盖onMeasure,因此它的高度和宽度将为零。

您的外部课程RingonLayout中没有执行任何操作,并告诉孩子应该在屏幕上绘制哪些内容,这样也会导致问题。十分之九,您将要想要子类化LinearLayout,RelativeLayout或FrameLayout,而不是ViewGroup,因此您不必覆盖onMeasureonLayout

但是,当只有一个子视图时,您是否有任何理由使用视图组?您似乎可以将onDraw方法移动到父Ring中,删除内部Ring_main类,并将Ring更改为子类View,并且您将完成大部分工作

修改 在以下评论中回复您的代码: 您的onMeasure实现是错误的,因为您忽略了附加到传入宽度和高度的可能模式。例如,在布局xml中,父级的高度为wrap_content,因此onMeasure的高度参数的模式为UNSPECIFIED,当您调用{{1}时它将返回一个无用的数字(虽然它似乎默认为零)。

这是一个更正确的实现,尽管最终会有更多细节需要考虑,例如您是否希望弧展开以填充视图可用的任何空间量,或者始终保持相同大小,只是在视图中居中。

MeasureSpec.getSize(aHeight)

如果您的min SDK为11或更高版本,使用static final float DESIRED_WIDTH_BEFORE_PADDING = 100; static final float DESIRED_HEIGHT_BEFORE_PADDING = 200; protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int wDesired = getPaddingLeft() + getPaddingRight() + Math.max(DESIRED_WIDTH_BEFORE_PADDING, getSuggestedMinimumWidth()); int wSpecMode = MeasureSpec.getMode(widthMeasureSpec); int w = 0; switch(wSpecMode){ case MeasureSpec.EXACTLY: w = MeasureSpec.getSize(widthMeasureSpec); break; case MeasureSpec.AT_MOST: w = Math.min(wDesired, MeasureSpec.getSize(widthMeasureSpec)); break; case MeasureSpec.UNSPECIFIED: w = wDesired; break; } int hDesired = getPaddingTop() + getPaddingBottom() + Math.max(DESIRED_HEIGHT_BEFORE_PADDING, getSuggestedMinimumHeight()); int hSpecMode = MeasureSpec.getMode(heightMeasureSpec); int h = 0; switch(hSpecMode){ case MeasureSpec.EXACTLY: h = MeasureSpec.getSize(heightMeasureSpec); break; case MeasureSpec.AT_MOST: h = Math.min(hDesired, MeasureSpec.getSize(heightMeasureSpec)); break; case MeasureSpec.UNSPECIFIED: h = hDesired; break; } setMeasuredDimension(w, h); } 方法可以简化这一过程。

注意上面的内容被简化为忽略DIP。这两个静态浮点数应该是DIP单位,然后在resolveSizeAndState中使用时将它们乘以密度。

您还可以覆盖onMeasure来计算用于绘制圆弧的实际高度和宽度,以及可能使弧在视图中居中所需的任何偏移。然后,这些值将在onSizeChanged中使用,以确保弧线绘制到您想要的位置。