Android Custom Layout - onDraw() never gets called

32,165

By default, onDraw() isn't called for ViewGroup objects. Instead, you can override dispatchDraw().

Alternatively, you can enable ViewGroup drawing by calling setWillNotDraw(false) in your TableView constructor.

EDIT:

For #2: - Initialize it in the constructor, then just call rect.set() in your onLayout() method.

For #3: - Yes, as far as I'm aware the super call will handle it, you shouldn't have to handle that unless you need to customize the way the children are drawn.

Share:
32,165
Ofek Ron
Author by

Ofek Ron

What can i say i like to code

Updated on July 09, 2022

Comments

  • Ofek Ron
    Ofek Ron almost 2 years
    public class MainActivity extends Activity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            TableView tv = new TableView(this);
            tv.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
            setContentView(tv);      
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            getMenuInflater().inflate(R.menu.activity_main, menu);
            return true;
        }
    }
    
    public class TableView extends ViewGroup {
        private Paint oval;
        private RectF rect;
    
        public TableView(Context context) {
            super(context);
            oval= new Paint(Paint.ANTI_ALIAS_FLAG);
            oval.setColor(Color.GREEN);
        }
    
    
        public void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawOval(rect , oval);
        }
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            int wspec = MeasureSpec.makeMeasureSpec(
                    getMeasuredWidth(), MeasureSpec.EXACTLY);
            int hspec = MeasureSpec.makeMeasureSpec(
                    getMeasuredHeight(), MeasureSpec.EXACTLY);
            for(int i=0; i<getChildCount(); i++){
                View v = getChildAt(i);
                v.measure(wspec, hspec);
            }
        }
    
    
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            float w=r-l;
            float h=b-t;
            rect=new RectF(w/8,h/8,7*w/8,7*h/8);
            float theta = (float) (2 * Math.PI / getChildCount());
            for(int i=0; i< getChildCount(); i++) {
                View v = getChildAt(i);
                w = (rect.right-rect.left)/2;
                h = (rect.bottom-rect.top)/2;
                float half = Math.max(w, h)/2;
                float centerX = rect.centerX()+w*FloatMath.cos(theta);
                float centerY = rect.centerY()+h*FloatMath.sin(theta);
                v.layout((int)(centerX-half),(int)(centerY-half),(int)(centerX+half),(int)(centerY+half));
            }
        }
    }
    

    Well there are almost NONE good and deep tutorials and hardly any piece of data on how to do custom layouts right, so i tried to figure out how its done, what i am trying to implement is a Layout that paints a green oval at the center of the screen, and i want every child of this layout to be layed out around the oval.

    you can think of that oval as a poker table that i want the children of this layout to seat around it.

    What currently happens by this code is that i get a white app scren with no oval, so i debugged it and saw that onDraw never gets called...

    3 questions:

    1. why is onDraw not getting called?
    2. the sdk warns me that i shouldnt allocate new objects within onLayout method, so where should i calculate the RectF so it is ready for the onDraw call to come?
    3. does calling super.onDraw() would make all children paint themselves? or should i explicitly invoke their draw()?

    If I got it all wrong and you guys can guide me in the right direction, or have any links to examples or tutorials related to this subject that would be helpful too!

  • Ofek Ron
    Ofek Ron over 11 years
    great that worked, thanks!, and what about my other questions?
  • lambruscoAcido
    lambruscoAcido about 10 years
    @kcoppock <br> The mentioned method name is not setWillNotDrawEnabled but simply setWillNotDraw (public method of the Viewclass).