2011-09-15 2 views
6

Я пишу приложение с единственной целью попытаться понять, как работает иерархия представлений в Android. Сейчас у меня есть некоторые серьезные проблемы. Я постараюсь дать краткое объяснение здесь.Попытка понять иерархию просмотров

В настоящее время у меня есть три Представления. 2 - ViewGroups, а 1 - только View. Допустим, они в таком порядке:

TestA extends ViewGroup 
    TestB extends ViewGroup 
    TestC extends View 
    TestA->TestB->TestC 
    Where TestC is in TestB and TestB is in TestA. 

В моей Activity я просто отобразить взгляды, как так:

TestA myView = new TestA(context); 
myView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT)); 
setContentView(myView); 

Проблемы:

  1. Метод Testa onDraw(Canvas canvas) никогда не является называется. Я видел пару решений этой фразы о том, что мой взгляд не имеет размеров (height/width = 0), однако это не так. Когда я переопределяю onLayout(), я получаю размеры моего макета, и они верны. Кроме того, getHeight()/Width() точно такие, какими они должны быть. Я также могу переопределить dispatchDraw() и получить свои базовые представления, чтобы нарисовать себя.

  2. Я хочу анимировать объект в TestB. Традиционно я бы переопределил метод onDraw() по вызову invalidate() сам по себе, пока объект не закончит анимацию, которую он должен был сделать. Однако в TestB, когда я звоню invalidate(), вид никогда не перерисовывается. У меня создается впечатление, что работа моего родительского представления снова вызывает метод onDraw(), но мое родительское представление снова не вызывает dispatchDraw().

Я думаю, мои вопросы, почему бы мой onDraw() метод моего родительского вида никогда не дозвонились начать? Какие методы в моем родительском представлении должны быть вызваны, когда один из его дочерних элементов недействителен? Является ли родитель ответственным за обеспечение того, чтобы дети были нарисованы или Android позаботился об этом? Если Android отвечает на invalidate(), почему мой TestB никогда не будет нарисован снова?

ответ

5

Хорошо, после некоторых исследований и много попыток, я обнаружил, что делал три вещи неправильно в отношении проблемы № 2. Многое было простым ответом, но не очень очевидным.

  • Для каждого вида необходимо переопределить onMeasure(). В пределах onMeasure() вам необходимо позвонить measure() за каждые ребенок, содержащийся в ViewGroup, проходящий в MeasureSpec, который нужен ребенку.

  • addView() для каждый ребенок, которого вы хотите включить. Первоначально я просто создал объект вида и использовал его напрямую.Это позволило мне нарисовать его один раз, но представление не было включено в дерево представлений, поэтому при вызове invalidate() это не привело к недействительности дерева представлений, а не перерисовке. Например:

В 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); 
} 

Это привлечёт вид ребенка один раз. Однако, если это представление нуждается в обновлении для анимации или что-то еще, то есть. Я положил 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); 
+0

вы можете поделиться этим демо-проектом Viewgroup в своем блоге или где-нибудь это будет очень полезно .. Спасибо mate .. – user1201239

+0

Мне нужно добавить childView, даже если мы укажем его в XML? – user1201239

+0

Прошу прощения. У меня нет блога или чего-либо еще для загрузки. Я постараюсь быть настолько полезной, насколько смогу. Чтобы ответить на ваш первый вопрос, нет. Когда вы надуваете xml, ребенок содержится в 'ViewGroup'. Самое раннее, что вы можете получить, это 'onFinishInflate()'. После этого у вас есть выбор. Либо получите своих детей с помощью метода getChildAt (int index) ', либо используйте' findViewById (int id) '. Индекс будет тем порядком, в котором дети находятся в xml. Я не знаю, как индексирование работает с детьми внутри детей. – DeeV

2

Это не прямой ответ, но here is a fantastic tutorial о том, как рисовать пользовательские виды и дает отличные возможности для того, чтобы анимировать представление. Код очень прост и чист.

Надеюсь, это поможет!

+0

Спасибо. Это не помогло решить мои проблемы, но это помогло в решении этого вопроса. – DeeV

Смежные вопросы