问题
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...
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 response 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 insideReflectingLayout
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.
回答1:
What about using getParent()
method in your view? Something like this:
if (getParent() instanceof View)
((View) getParent()).invalidate();
回答2:
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);
}
来源:https://stackoverflow.com/questions/7753358/how-do-i-trigger-the-redraw-of-a-parent-view-when-any-of-its-children-are-redra