Подтвердить что ты не робот

Как вызвать перерисовку родительского представления, когда кто-либо из его детей перерисовывается?

Фон

Я написал пользовательский Android-вид на основе LinearLayout, который я назвал ReflectingLayout. Идея довольно проста, чтобы сделать эффект отражения ниже любого дочернего вида, объявленного в ReflectingLayout. например...

Something like this

Я достигаю этого, переопределяя dispatchDraw() в ReflectingLayout следующим образом:

@Override
protected void dispatchDraw(Canvas canvas) {

  Bitmap bitmap = Bitmap.createBitmap(...); 
  Canvas tempCanvas = new Canvas(bitmap);

  // Draw child views to bitmap using tempCanvas
  super.dispatchDraw(tempCanvas);

  ...
  // some tranformations performed on bitmap
  ...

  // draw transformed image on to main canvas
  canvas.drawBitmap(bitmap, 0, 0, null);
}

Проблема

Если my ReflectingLayout содержит, скажем, a TextView, и я изменяю текстовое содержимое этого TextView, эффект отражения не обновляется.

Я считаю, что это связано с тем, что Android будет перерисовывать только TextView, а не все родительские представления, то есть мой переопределенный метод dispatchDraw() не будет вызван.

Есть ли какой-либо простой способ вызвать перерисовку родительского представления в ответ на изменения в любом из его дочерних представлений?

В частности, как сделать, чтобы мой ReflectingLayout был перерисован при перерисовании дочерних просмотров?

Вещи, которые я уже рассмотрел

  • Я заметил, что в API уровня 11 добавлен новый View.OnLayoutChangeListener. Предположительно это можно было бы использовать для регистрации обратный вызов родительского представления и запуск перерисовки (?). В любом случае мне нужно решение, которое будет работать над API уровня 7 вверх.

  • Я мог бы просто расширить TextView и любой другой класс представления, который я хочу объявить внутри ReflectingLayout, чтобы сделать недействительным их родительский объект, поскольку они перерисовываются, но это неуклюжее решение.

Любая полученная помощь (в том числе, если вы считаете, что общий подход неверен).

Спасибо.

4b9b3361

Ответ 1

Как насчет использования метода getParent() в вашем представлении? Что-то вроде этого:

if (getParent() instanceof View)
    ((View) getParent()).invalidate();

Ответ 2

Я просто столкнулся с этой проблемой. Я понял, что это связано с новой поддержкой аппаратного ускорения в версии 3.0+. Как я решил, он использовал View#setLayerType и использовал LAYER_TYPE_SOFTWARE. Чтобы продолжить таргетинг на уровень API 8, я использовал отражение, чтобы вызвать этот метод для поддержки платформ Android. Это решило проблему, и теперь моя пользовательская ViewGroup правильно рисует, когда дети недействительны.

Я не знаю, поможет ли это решить вашу проблему, но это может помочь другим, которые также озадачены этой проблемой.

Код отражения, довольно простой:

try {
    Method method =
            CustomViewGroup.class.getMethod("setLayerType", new Class[] { Integer.TYPE, Paint.class });
    // 0x1 == LAYER_TYPE_SOFTWARE
    method.invoke(this, new Object[] { Integer.valueOf(0x1), null });
} catch(SecurityException e) {
    Log.e(TAG, "reflectSetLayerType", e);
} catch(NoSuchMethodException e) { // don't care
} catch(IllegalArgumentException e) {
    Log.e(TAG, "reflectSetLayerType", e);
} catch(IllegalAccessException e) {
    Log.e(TAG, "reflectSetLayerType", e);
} catch(InvocationTargetException e) {
    Log.e(TAG, "reflectSetLayerType", e);
}