samedi 3 octobre 2015

Why is my android view's width 0?

I created a custom view called CanvasView. I can use this view to draw stuff on it outside of the onDraw method. Which means I can add lines, circles, whatever I want to the canvas anywhere in my code.

I want to draw a random line on the canvas view in the onCreate method. I want the starting point to be in the left half of the view and the ending point in the right half. However, when I measure the width of the view using getWidth, it returns 0! And then I pass this number into Random.nextInt with some more calculations. And resulting in a negative number. An IllegalArgumentException occurs as expected.

I just want to ask why my view's width is 0? And how can I get the correct width?

Here is the CanvasView class: (methods other than addShape and onDraw are irrelevant, I think)

public class CanvasView extends View {
    /**
     * Stores all the shapes that the view will draw in its {@code onDraw()}
     * method
     */
    private ArrayList<Shape> shapes;

    /**
     * Represents a standard {@code Paint} object that should be used when
     * drawing on this {@code CanvasView}.
     */
    private Paint paint;

    public CanvasView(Context c) {
        super (c);
        init ();
    }

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

    public CanvasView(Context context, AttributeSet attrs, int defStyleAttr) {
        super (context, attrs, defStyleAttr);
        init ();
    }

    /**
     * Initializes the view, called by the constructor.
     */
    private void init() {
        shapes = new ArrayList<> ();
        paint = new Paint ();
        paint.setStrokeWidth (5);
        paint.setColor (Color.BLACK);
    }

    @Override
    public void setOnTouchListener(final OnTouchListener listener) {
        final OnTouchListener baseListener = new OnTouchListener () {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction () == MotionEvent.ACTION_DOWN) {

                    float x = event.getX ();
                    float y = event.getY ();

                    Log.d ("My App", "X: " + x);
                    Log.d ("My App", "Y: " + y);

                    //check whether the point touched is in bounds
                    if (x < 18 || x > getWidth () - 18 || y < 18 ||
                            y > getHeight () - 18)
                        return false;
                    else
                        return true;
                }
                return false;
            }
        };

        super.setOnTouchListener (new OnTouchListener () {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (baseListener.onTouch (v, event)) {
                    if (listener != null) {
                        return listener.onTouch (v, event);
                    } else {
                        return true;
                    }
                }
                return false;
            }
        });
    }

    @Override
    protected void onDraw(Canvas c) {
        super.onDraw (c);
        for (Shape s : shapes) {
            s.draw (c);
        }
        //draw the border.
        c.drawLine (3, 3, getWidth () - 3, 3, paint);
        c.drawLine (3, getHeight () - 3, getWidth () - 3, getHeight () - 3, paint);
        c.drawLine (3, 3, 3, getHeight () - 3, paint);
        c.drawLine (getWidth () - 3, 3, getWidth () - 3, getHeight () - 3, paint);

        //draw the inner border
        c.drawLine (18, 18, getWidth () - 18, 18, paint);
        c.drawLine (18, getHeight () - 18, getWidth () - 18, getHeight () - 18, paint);
        c.drawLine (18, 18, 18, getHeight () - 18, paint);
        c.drawLine (getWidth () - 18, 18, getWidth () - 18, getHeight () - 18, paint);
    }

    /**
     * Adds a shape to the {@code CanvasView} so that it can be drawn
     * in its {@code onDraw()} method.
     *
     * @param s
     */
    public void addShape(Shape s) {
        shapes.add (s);
        invalidate ();
    }

    /**
     * Clears all the shapes on the {@code CanvasView}.
     */
    public void clear() {
        shapes.clear ();
    }
}

There is a Shape interface that I created, which only has this method:

void draw (Canvas c);

Here is how I draw a random line, this snippt is in a method that is called in onCreate:

Random r = new Random ();
final int width = canvas.getWidth () - 30;
final int height = canvas.getHeight () - 30;
final Paint p = paint;

final int startX = r.nextInt ((width - 30) / 2) + 30;
final int startY = r.nextInt (height - 30) + 30;
final int stopX = r.nextInt ((width - 30) / 2) + width / 2 + 30;
final int stopY = r.nextInt (height - 30) + 30;

float adjSide = Math.abs (stopX - startX);
float oppSide = Math.abs (stopY - startY);
lineAngle = (float)Math.atan (oppSide / adjSide);

canvas.addShape (new Shape () {
    @Override
    public void draw(Canvas c) {
        c.drawLine (startX, startY, stopX, stopY, p);
    }
});




Aucun commentaire:

Enregistrer un commentaire