Хорошо, после некоторого исследования и много попыток, я обнаружил, что я делал три вещи неправильно в отношении проблемы # 2. Во многом это были простые ответы, но не очень очевидные.
Вам необходимо переопределить onMeasure()
для каждого просмотра. В пределах onMeasure()
вам необходимо вызвать measure()
для каждого дочернего элемента, содержащегося в передаче ViewGroup
в MeasureSpec, в которой нуждается дочерний элемент.
Вам нужно позвонить addView()
для каждого ребенка, которого вы хотите включить. Первоначально я просто создал объект просмотра и использовал его напрямую. Это позволило мне нарисовать его один раз, но представление не было включено в дерево представления, поэтому при вызове invalidate()
оно не аннулировало дерево представления и не перерисовало. Например:
В тесте A:
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);
}
Это нарисует дочерний вид один раз. Однако, если это представление нуждается в обновлении для анимации или чего-то еще, это было так Я добавил addView(childView)
в конструктор 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);
addView(childView);
}
@Override
protected void dispatchDraw(Canvas canvas){
childView.draw(canvas);
}
В качестве альтернативы, я мог бы переопределить dispatchDraw(Canvas canvas)
примерно так, если бы у меня было много детей для рисования, но мне нужен какой-то пользовательский элемент между каждым рисунком, например, линии сетки или что-то в этом роде.
@Override
protectd void dispatchDraw(Canvas canvas){
int childCount = getChildCount();
for(int i = 0; i < size; i++)
{
drawCustomElement();
getChildAt(i).draw(canvas);
}
}
- Вы должны переопределить
onLayout()
(в любом случае оно абстрактно в ViewGroup
, так что в любом случае требуется). В рамках этого метода вы должны вызывать layout
для каждого ребенка. Даже после выполнения первых двух вещей мои взгляды не станут недействительными. Как только я это сделал, все заработало просто отлично.
UPDATE:
Проблема № 1 была решена. Другое чрезвычайно простое, но не столь очевидное решение.
Когда я создаю экземпляр TestA
, мне нужно позвонить setWillNotDraw(false)
, иначе Android не будет его рисовать по причинам оптимизации. Итак, полная настройка:
TestA myView = new TestA(context);
myView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT));
myView.setWillNotDraw(false);
setContentView(myView);