Search code examples
androidandroid-custom-view

Android add two views with canvases programmatically


I have been trying to add two views with canvases to my activity programmatically, but it looks like only the first one is being added (I can tell by looking at the console output). What am I doing wrong?

Here is my code:

package app.com.example.android.drawtwoviews;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity {
    DrawView drawView;
    DrawView2 drawView2;
    private LinearLayout root;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        root = new LinearLayout(this);
        root.setOrientation(LinearLayout.VERTICAL);

        drawView = new DrawView(this);
        drawView.setBackgroundColor(Color.WHITE);
        root.addView(drawView);

        drawView2 = new DrawView2(this);
        drawView2.setBackgroundColor(Color.WHITE);
        root.addView(drawView2);

        setContentView(root);
    }

    public class DrawView extends View {
        Paint paint = new Paint();

        public DrawView(Context context) {
            super(context);
        }

        @Override
        public void onDraw(Canvas canvas) {
            System.out.println("DrawView1");
            paint.setColor(Color.BLACK);
            //paint.setStrokeWidth(3);
            canvas.drawRect(30, 30, 80, 80, paint);


        }

    }


    public class DrawView2 extends View {
        Paint paint = new Paint();

        public DrawView2(Context context) {
            super(context);
        }

        @Override
        public void onDraw(Canvas canvas) {
            System.out.println("DrawView2");
            paint.setColor(Color.BLUE);
            paint.setStrokeWidth(3);
            canvas.drawRect(300, 300, 400, 400, paint);


        }

    }
}

Solution

  • You are adding your views to the root without specifying layout parameters. That means they both get the default layout parameters of LinearLayout, which, for a vertical layout, is (MATCH_PARENT, WRAP_CONTENT).

    Neither of your custom views overrides onMeasure(), which means both measure to their default suggested minimum size of 0×0.

    This means that your LinearLayout is layouting two views with a requested size of 0×0 and a layout spec of (MATCH_PARENT, WRAP_CONTENT). The way this works out is a bit tricky, but your first child takes up the full screen height and your second child is 0px tall. Both children are full screen width. You can easily see this in the Hierarchy Viewer.

    To fix the problem, you need to either specify layout params:

    // in onCreate()
    int width = LinearLayout.LayoutParams.MATCH_PARENT;
    int height = 0;
    int weight = 1;
    LinearLayout.LayoutParams params = 
        new LinearLayout.LayoutParams(width, height, weight);
    
    drawView = new DrawView(this);
    drawView.setBackgroundColor(Color.WHITE);
    root.addView(drawView, params); // note the extra argument
    
    drawView2 = new DrawView2(this);
    drawView2.setBackgroundColor(Color.WHITE);
    root.addView(drawView2, params); // note the extra argument
    

    Or you can modify the DrawViews so that they measure to some minimum size:

    public class DrawView extends View {
        // paint
        // constructor
        // onDraw
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
        {
            setMeasuredDimension(80, 80);
        }
    }
    
    
    public class DrawView2 extends View {
        // paint
        // constructor
        // onDraw
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
        {
            setMeasuredDimension(400, 400);
        }
    }