开发者

How do I trigger the redraw of a parent View when any of it's children are redrawn?

开发者 https://www.devze.com 2023-04-12 14:14 出处:网络
Background I have written a custom Android View based on a LinearLayout which I have called ReflectingLayout. The idea is fairly simple, to render a reflection effect below any child Views declared w

Background

I have written a custom Android View based on a LinearLayout which I have called ReflectingLayout. The idea is fairly simple, to render a reflection effect below any child Views declared within the ReflectingLayout. e.g...

Something like this

I am achieving this by overriding dispatchDraw() in ReflectingLayout as follows:

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

The Problem

If my ReflectingLayout contains, say, a TextView and I change the text content of that TextView the reflection effect is not updating.

I believe this is because Android will only redraw the TextView itself rather than all the parent views as well, meaning my overridden dispatchDraw() method does not get called.

Is there any simple way to trigger the redrawing of a parent view in resp开发者_如何学JAVAonse to changes in any of it's child views?

In particular, how can I make my ReflectingLayout be redrawn when child views are redrawn?

Things I've already considered

  • I've noticed that a new View.OnLayoutChangeListener was added in API Level 11. Presumably this could be used to register a callback to the parent view and trigger a redraw(?). In any case, I need a solution which will work on API Level 7 upwards.

  • I could simply extend TextView and any other View class I want to declare inside ReflectingLayout to invalidate their parent as they are redrawn, but this is a clunky solution.

Any help greatly received (including if you think the overall approach is wrong).

Thanks.


What about using getParent() method in your view? Something like this:

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


I just encountered this problem. I figured out it was due to the new hardware acceleration support in 3.0+ The way I solved it was using View#setLayerType and using LAYER_TYPE_SOFTWARE. In order to continue targeting API level 8 I used reflection to call this method on supporting android platforms. This solved the issue and now my custom ViewGroup draws properly when the children are invalidated.

I don't know if this will solve your problem exactly but it may help others who are also perplexed by this issue.

Reflection code, pretty basic:

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

精彩评论

暂无评论...
验证码 换一张
取 消