当父视图的任何子视图重绘时,如何触发父视图的重绘?

发布于 2024-12-09 18:43:01 字数 1626 浏览 0 评论 0原文

背景

我已经编写了一个基于 LinearLayout 的自定义 Android 视图,我将其称为 ReflectingLayout。这个想法相当简单,在 ReflectingLayout 中声明的任何子视图下方渲染反射效果。例如..

类似这样的

我通过重写 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 的文本内容code> 反射效果未更新。

我相信这是因为 Android 只会重绘 TextView 本身,而不是重绘所有父视图,这意味着我重写的 dispatchDraw() 方法不会被调用。

是否有任何简单的方法可以触发父视图的重绘以响应其任何子视图的更改?

特别是,如何使我的 ReflectingLayout 在以下情况下重绘:子视图被重绘?

我已经考虑过的事情

  • 我注意到一个新的 View.OnLayoutChangeListener 已在 API 级别 11 中添加。大概这可用于注册父视图的回调并触发重绘(?)。无论如何,我需要一个可以在 API 7 级以上运行的解决方案。

  • 我可以简单地扩展 TextView 和我想在 ReflectingLayout 中声明的任何其他 View 类,以在重绘时使它们的父级无效,但这是一个笨拙的解决方案。

收到的任何帮助(包括您认为整体方法是错误的)。

谢谢。

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 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 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

娇纵 2024-12-16 18:43:01

在您的视图中使用 getParent() 方法怎么样?像这样的事情:

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

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

if (getParent() instanceof View)
    ((View) getParent()).invalidate();
夏日落 2024-12-16 18:43:01

我刚刚遇到这个问题。我发现这是由于 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);
}

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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文