为什么在change = false时重复调用view.onLayout()?

时间:2013-10-07 14:39:04

标签: android android-layout android-custom-view

来自官方文档:

Android Docs - View

protected void onLayout (boolean changed, int left, int top, int right, int bottom)

Parameters
changed This is a new size or position for this view
left    Left position, relative to parent
top     Top position, relative to parent
right   Right position, relative to parent
bottom  Bottom position, relative to parent 

为什么我的自定义视图会被changed=false重复调用?这是正常的吗?

这是调用树:

Synoptic.onLayout(boolean, int, int, int, int) line: 130    
Synoptic(View).layout(int, int, int, int) line: 11282   
Synoptic(ViewGroup).layout(int, int, int, int) line: 4224   
RelativeLayout.onLayout(boolean, int, int, int, int) line: 925  
RelativeLayout(View).layout(int, int, int, int) line: 11282 
RelativeLayout(ViewGroup).layout(int, int, int, int) line: 4224 
LinearLayout.setChildFrame(View, int, int, int, int) line: 1628 
LinearLayout.layoutHorizontal() line: 1617  
LinearLayout.onLayout(boolean, int, int, int, int) line: 1401   
LinearLayout(View).layout(int, int, int, int) line: 11282   
LinearLayout(ViewGroup).layout(int, int, int, int) line: 4224   
SwipeView(FrameLayout).onLayout(boolean, int, int, int, int) line: 431  
SwipeView(HorizontalScrollView).onLayout(boolean, int, int, int, int) line: 1382    
SwipeView.onLayout(boolean, int, int, int, int) line: 154   
SwipeView(View).layout(int, int, int, int) line: 11282  
SwipeView(ViewGroup).layout(int, int, int, int) line: 4224  
LinearLayout.setChildFrame(View, int, int, int, int) line: 1628 
LinearLayout.layoutVertical() line: 1486    
LinearLayout.onLayout(boolean, int, int, int, int) line: 1399   
LinearLayout(View).layout(int, int, int, int) line: 11282   
LinearLayout(ViewGroup).layout(int, int, int, int) line: 4224   
FrameLayout.onLayout(boolean, int, int, int, int) line: 431 
FrameLayout(View).layout(int, int, int, int) line: 11282    
FrameLayout(ViewGroup).layout(int, int, int, int) line: 4224    
LinearLayout.setChildFrame(View, int, int, int, int) line: 1628 
LinearLayout.layoutVertical() line: 1486    
LinearLayout.onLayout(boolean, int, int, int, int) line: 1399   
LinearLayout(View).layout(int, int, int, int) line: 11282   
LinearLayout(ViewGroup).layout(int, int, int, int) line: 4224   
PhoneWindow$DecorView(FrameLayout).onLayout(boolean, int, int, int, int) line: 431  
PhoneWindow$DecorView(View).layout(int, int, int, int) line: 11282  
PhoneWindow$DecorView(ViewGroup).layout(int, int, int, int) line: 4224  
ViewRootImpl.performTraversals() line: 1514 
ViewRootImpl.handleMessage(Message) line: 2467  
ViewRootImpl(Handler).dispatchMessage(Message) line: 99 
Looper.loop() line: 137 
ActivityThread.main(String[]) line: 4424    
Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]  
Method.invoke(Object, Object...) line: 511  
ZygoteInit$MethodAndArgsCaller.run() line: 784  
ZygoteInit.main(String[]) line: 551 
NativeStart.main(String[]) line: not available [native method]  

2 个答案:

答案 0 :(得分:11)

文档中的关键部分是:

当此视图应为每个子视图指定大小和位置时,从布局调用。

如果ViewGroup中的View设置为wrap_content并且它的大小发生改变(例如TextView中的文本更改为更长的字符串),则会发生ViewGroup中的onLayout。这是因为视图在布局时会给出它们的大小,因此如果没有调用,View将永远不会被赋予新的大小。

答案 1 :(得分:7)

我发现了问题:对于像我这样的复合组件,其中包含TextView,对.setText()的重复调用会导致调用父onLayout()

...即使新文本等于当前TextView文本!

所以我解决了:

public void setTextViewText(String text) {
    if (!this.textViewValue.getText().equals(text)) {
        this.textViewValue.setText(text);
    }
}