Well, after some research and many attempts, I found that I was doing three things wrong with respect to Problem 2. Many of them were simple answers, but not very obvious.
You need to override onMeasure()
for each view. Within onMeasure()
you need to call measure()
for each child contained in the ViewGroup
passing in the MeasureSpec that the child needs.
You need to call addView()
for each child you want to include. Initially, I just created a view object and used it directly. This allowed me to draw it once, but the view was not included in the view tree, so when I called invalidate()
it did not invalidate the view tree, not redraw it. For instance:
In testA:
TestB childView; TestA(Context context){ ****** setup code ******* LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); childView = new TestB(context); childView.setLayoutParams(params); } @Override protected void dispatchDraw(Canvas canvas){ childView.draw(canvas); }
This will draw the child view once. However, if this view needs to be updated for animation or something else, that is. I put addView(childView)
in the TestA constructor to add it to the view tree. The final code is as follows:
TestB childView; TestA(Context context){ ****** setup code ******* LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); childView = new TestB(context); childView.setLayoutParams(params); addView(childView); } @Override protected void dispatchDraw(Canvas canvas){ childView.draw(canvas); }
Alternatively, I could redefine dispatchDraw(Canvas canvas)
so that I would have many more children, but I need some kind of custom element between each drawing, like grid lines or something like that.
@Override protectd void dispatchDraw(Canvas canvas){ int childCount = getChildCount(); for(int i = 0; i < size; i++) { drawCustomElement(); getChildAt(i).draw(canvas); } }
- You must override
onLayout()
(this is abstract in the ViewGroup
, one way or another, as it was required). As part of this method, you must call layout
for each child. Even after the first two things, my views will not be invalidated. As soon as I did this, everything worked perfectly.
UPDATE: Problem number 1 solved. Another extremely simple, but not so obvious solution.
When I create an instance of TestA
, I have to call setWillNotDraw(false)
, otherwise Android will not draw it for optimization reasons. Thus, the full setup:
TestA myView = new TestA(context); myView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT)); myView.setWillNotDraw(false); setContentView(myView);