Android 自定义视图组中的视图在大小更改后不进行渲染

Android 自定义视图组中的视图在大小更改后不进行渲染,android,resize,rendering,custom-view,viewgroup,Android,Resize,Rendering,Custom View,Viewgroup,我遇到了一个让我困惑的问题,我希望有人能给我一些建议 我正在开发一个使用自定义视图组(实际上是一个包含RelativeLayout的FrameLayout)来呈现事件日历的应用程序。日历中的事件表示为视图,视图的大小取决于事件的持续时间和包含视图的大小 我遇到了一个在调整包含框架布局的大小时发生的问题。当前实现将删除表示事件的所有视图,并尝试添加新视图,并根据FrameLayout的当前大小计算其大小。这项工作是通过视图的onSizeChanged()方法触发的,该方法在FrameLayout中

我遇到了一个让我困惑的问题,我希望有人能给我一些建议

我正在开发一个使用自定义视图组(实际上是一个包含RelativeLayout的FrameLayout)来呈现事件日历的应用程序。日历中的事件表示为视图,视图的大小取决于事件的持续时间和包含视图的大小

我遇到了一个在调整包含框架布局的大小时发生的问题。当前实现将删除表示事件的所有视图,并尝试添加新视图,并根据FrameLayout的当前大小计算其大小。这项工作是通过视图的onSizeChanged()方法触发的,该方法在FrameLayout中被重写

当视图调整大小时,将执行此代码并更新视图,但是,没有一个视图实际呈现在屏幕上。。。FrameLayout中包含的视图根本不可见。如果我在hierarchyviewer工具中加载视图,则它们是视图树的一部分,并在概览中以它们应该位于的位置进行概述,但它们不会显示。(请注意,视图在FrameLayout的初始渲染时可见……只有在调整大小后它们才会消失。)

调整大小过程中的事件顺序似乎如下所示:

onMeasure()
onMeasure()
onSizeChanged()
onLayout()
onMeasure()
onMeasure()
onSizeChanged()
onLayout()
onMeasure()
onMeasure()
onLayout()
重置视图(在onSizeChanged()内)后调用requestLayout()似乎没有效果。但是,如果在调用requestLayout()之前造成一些延迟,则视图将可见。我可以通过生成一个线程并休眠,或者创建一个只调用requestLayout()并在调整大小后按下它的虚拟按钮,或者甚至是在onSizeChanged()末尾的这个丑陋的hack来造成延迟:

当我使用这个hack时,包含的视图是可见的,事件的顺序如下:

onMeasure()
onMeasure()
onSizeChanged()
onLayout()
onMeasure()
onMeasure()
onSizeChanged()
onLayout()
onMeasure()
onMeasure()
onLayout()
因此,强制执行第二个度量过程(在修改视图树之后)似乎会使包含的视图按其应有的方式可见。为什么延迟对requestLayout()的调用,这对我来说是个谜

有人能给我指点我做错了什么吗

我意识到,不看一些代码就很难理解这一点,因此我创建了一个小示例应用程序,展示了我的问题,并在Github上提供了它:

我上面提到的黑客是由一个单独的分支机构负责的:


如果我能提供任何其他信息,请提前告诉我并表示感谢。

这不是黑客攻击,而是它的工作原理。onSizeChanged()作为布局过程的一部分调用,在布局过程中不能/不应该请求layout()。在事件队列上发布requestLayout()以指示您在布局过程中更改了视图层次结构是正确的。

我遇到了相同的问题

我的onMeasure()是这样的:

@Override    
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        ...
        //calculate new width and height here
        ...
        setMeasuredDimension(newMeasureSpecWidth, newMeasureSpecHeight);
    }
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    ...
    //calculate new width and height here
    ...
    int newMeasureSpecWidth = MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY);
    int newMeasureSpecHeight = MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY);
    super.onMeasure(newMeasureSpecWidth, newMeasureSpecHeight);
}
我的错误是我在onMeasure()的第一行调用super.onMeasure(),所以我的视图组的内部子级是根据即将改变的大小计算的

所以我的修复程序是这样做的:

@Override    
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        ...
        //calculate new width and height here
        ...
        setMeasuredDimension(newMeasureSpecWidth, newMeasureSpecHeight);
    }
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    ...
    //calculate new width and height here
    ...
    int newMeasureSpecWidth = MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY);
    int newMeasureSpecHeight = MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY);
    super.onMeasure(newMeasureSpecWidth, newMeasureSpecHeight);
}
因此,我使用对super.onMeasure()的调用为我的视图组设置新的大小,然后它还将新的大小传递给它的子对象


记住:重写onMeasure()时的约定是必须调用setMeasuredDimension()(您可以通过调用方法本身或调用super.onMeasure()来实现这一点)

!非常感谢您花时间回答。当onMeasure()在事件队列上发布requestLayout()时,为什么他会遵循onLayout()而不是onDraw()?该死,我已经搜索了几个小时了。如果您使用addViewInLayout开发一个与ListView类似的自定义布局,请记住此功能-您必须通过Runnalbe发布requestLayout事件,以便在添加所有视图后刷新度量值