Как запустить перерисовку родительского представления, когда перерисовывается любой из его дочерних элементов? - PullRequest
11 голосов
/ 13 октября 2011

Фон

Я написал собственный Android View на основе 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);
}

Проблема

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

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

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

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

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

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

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

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

Спасибо.

Ответы [ 2 ]

6 голосов
/ 31 мая 2013

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

if (getParent() instanceof View)
    ((View) getParent()).invalidate();
1 голос
/ 26 июля 2013

Я только что столкнулся с этой проблемой. Я понял, что это связано с новой поддержкой аппаратного ускорения в версии 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);
}
...