2011-05-02 92 views
19

我遇到了一個問題,讓我難以忍受,我希望有人能給我一些指示。自定義ViewGroup中的視圖不會在大小更改後顯示

我正在使用自定義ViewGroup(實際上是一個包含RelativeLayout的FrameLayout)來呈現事件日曆的應用程序。日曆內的事件表示爲根據事件的持續時間和包含視圖的大小來確定大小的視圖。

我遇到了包含FrameLayout調整大小時發生的問題。當前實現刪除所有表示事件的視圖,並嘗試添加新視圖並根據FrameLayout的當前大小計算它們的大小。這項工作是通過在FrameLayout中重寫的View的onSizeChanged()方法觸發的。

當調整視圖大小時,會執行此代碼並更新視圖,但是,它們實際上都不會在屏幕上呈現...... FrameLayout中包含的視圖根本不可見。如果我在層次結構查看器工具中加載視圖,它們是視圖樹的一部分,並在概述中列出了它們應該位於的位置,但它們不顯示。 (請注意,意見是對初始可見渲染的FrameLayout的...這只是他們消失後,調整大小的。)

看來,事件的大小調整期間,順序如下:

onMeasure() 
onMeasure() 
onSizeChanged() 
onLayout() 

重置視圖(在onSizeChanged()內部)後調用requestLayout()似乎沒有效果。但是,如果在調用requestLayout()之前造成一些延遲,則視圖將變爲可見。我可以通過產生線程和睡眠,或者通過創建一個簡單地調用requestLayout()並在調整大小後按下它的虛擬按鈕,或者甚至將這個醜陋的黑客放在onSizeChanged()的末尾來導致此延遲:

post(new Runnable() { 
    public void run() { 
     requestLayout(); 
    } 
}); 

當我使用這個技巧,所包含的觀點是可見的,事件的順序如下:

onMeasure() 
onMeasure() 
onSizeChanged() 
onLayout() 
onMeasure() 
onMeasure() 
onLayout() 

所以看來迫使第二招通(視圖樹後已被修改),使所包含的視圖應該是可見的。爲什麼延遲對requestLayout()的調用對我來說這是一個謎。

任何人都可以提供任何指針,我做錯了什麼?

我知道這有些難以遵循不看一些代碼,所以我創建了展現我的問題一個小示例應用程序,並使其可在Github上:

https://github.com/MichaelSims/ViewGroupResizeTest

的黑客攻擊我上述承諾一個單獨的分支:

https://github.com/MichaelSims/ViewGroupResizeTest/tree/post-runnable-hack

如果我可以提供任何其他信息,請讓我知道,在此先感謝。

回答

25

這不是黑客,它是如何工作的。 onSizeChanged()作爲佈局過程的一部分被調用,並且在佈局過程中不能/不應該使用requestLayout()。在事件隊列上發佈requestLayout()以表明您在佈局過程中更改了View層次結構是正確的。

+0

太棒了!非常感謝您花時間回答。 – 2011-05-02 14:25:13

+0

不客氣:) – 2011-05-02 16:36:16

+0

當他在事件隊列上發佈requestLayout()時,爲什麼onMeasure()會跟上onLayout()而不是onDraw()? – futurexiong 2013-08-27 11:46:55

0

我遇到了同樣的問題。

我onMeasure()是這樣的:

@Override  
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
     super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
     ... 
     //calculate new width and height here 
     ... 
     setMeasuredDimension(newMeasureSpecWidth, newMeasureSpecHeight); 
    } 

我的錯誤是,我是在onMeasure()的第一行調用super.onMeasure(),所以我的ViewGroup內孩子們那時根據即將更改的大小計算。

所以我修復在做這樣的事情:

@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()的新的大小設置爲我的ViewGroup中,然後它也傳達了新的大小它的孩子。

記住:當你重寫onMeasure(合同)是你必須調用setMeasuredDimension()(你可以通過調用方法本身或致電super.onMeasure()實現這一點)

相關問題