Android 中的自定义视图显示为黑框

Custom View in Android shows up as a black box

我正在尝试创建类似饼图的视图,但我对 Android 还很陌生,所以它并不总是按照我的计划进行。现在,如果我真的在我的 activity 中得到黑盒子以外的东西,我会很高兴 :) 你能帮忙吗?

这是我的代码:

activity_main.xml

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="@dimen/activity_vertical_margin"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <TextView
        android:text="@string/hello_world"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <com.example.wouter.countdownwidget.PieHolder
        android:id="@+id/pieHolder"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </com.example.wouter.countdownwidget.PieHolder>

</LinearLayout>

MainActivity.java

public class MainActivity extends Activity {

    private static final String LOG_TAG = "MainActivity";

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

        PieHolder pieHolder = (PieHolder) findViewById(R.id.pieHolder);
        pieHolder.addInterval(new Interval(1, Color.RED));
    }
}

PieHolder.java

public class PieHolder extends ViewGroup {

    private static final String LOG_TAG = "PieHolder";

    private RectF pieBounds = new RectF();
    private PieView pieView;

    public PieHolder (Context context) {
        super(context);
        init();
    }

    public PieHolder (Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init () {
        setBackgroundColor(Color.WHITE);
        pieView = new PieView(this);
        addView(pieView);
    }

    void addInterval (Interval interval) {
        pieView.addInterval(interval);
    }

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

        float xpad = (float) (getPaddingLeft() + getPaddingRight());
        float ypad = (float) (getPaddingTop() + getPaddingBottom());
        float ww = (float) w - xpad;
        float hh = (float) h - ypad;
        float diameter = Math.min(ww, hh);

        pieBounds = new RectF(0, 0, diameter, diameter);
        pieBounds.offsetTo(getPaddingLeft(), getPaddingTop());

        pieView.layout((int) pieBounds.left,
                              (int) pieBounds.top,
                              (int) pieBounds.right,
                              (int) pieBounds.bottom);
    }

    @DebugLog @Override protected void dispatchDraw (Canvas canvas) {
        super.dispatchDraw(canvas);
        if (pieView != null) pieView.draw(canvas);
    }

    @Override protected void onLayout (boolean changed, int l, int t, int r, int b) {

    }
}

PieView.java

public class PieView extends SurfaceView{

    private static final String LOG_TAG = "PieView";

    private PieHolder pieHolder;
    //private SurfaceHolder holder;
    //private PieViewThread pieViewThread;

    private RectF rectF;
    private Paint paint;
    private List<Interval> intervals;

    @DebugLog public PieView (PieHolder pieHolder) {
        super(pieHolder.getContext());

        this.pieHolder = pieHolder;
        intervals = new ArrayList<>();
        rectF = new RectF(0, 0, pieHolder.getWidth(), pieHolder.getHeight());

        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.GREEN);
    }

    public void addInterval (Interval interval) {
        intervals.add(interval);
    }

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

        if (rectF == null) {
            rectF = new RectF(0, 0, pieHolder.getWidth(), pieHolder.getHeight());
            Log.i(LOG_TAG, "Reinstantiating rectF");
        }

        canvas.drawColor(Color.RED);
        canvas.drawArc(rectF, 0, 180, true, paint);
    }
}

您自定义了一个视图组,但其中没有任何内容。如果你只是想做一个视图,你最好从View而不是ViewGroup扩展。

您可以参考 google android 网站的文档:http://developer.android.com/training/custom-views/create-view.html

我找到解决方法了!!!

Android 期望在另一个线程中绘制 SurfaceView,因此我需要在 PieView 的构造函数中调用 setWillNotDraw(false)。此外,正如谢所说,创建自定义 ViewGroup 有点毫无意义,所以我也摆脱了它。

这是我的 PieView class 对于那些感兴趣的人:

class PieView extends SurfaceView{

    private Interval[] intervals;
    private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private RectF rectf;
    private int size;

    public PieView (Context context, Interval[] intervals) {
        super(context);
        this.intervals = intervals;
    setWillNotDraw(false);
    }

    @Override protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        size = Math.min(getMeasuredWidth(), getMeasuredHeight());
        setMeasuredDimension(size, size);
        if (rectf == null || rectf.width() != size ) { rectf = new RectF(0, 0, size, size); }
    }

    @Override protected void onDraw (Canvas canvas) {
        super.onDraw(canvas);
    canvas.drawColor(getResources().getColor(android.R.color.background_light));
        paint.setColor(intervals[0].color);
        canvas.drawArc(rectf, -90, 360, true, paint);
        paint.setColor(intervals[1].color);
        canvas.drawArc(rectf, -90, intervals[1].duration, true, paint);
    }
}

PS: 这绝不是我的最终目标,但现在我至少在我的屏幕上画了一些东西