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

Ser*_*m's 8 android android-custom-view android-layout

来自官方文档:

Android文档 - 查看

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 
Run Code Online (Sandbox Code Playgroud)

为什么我的自定义视图被重复调用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]  
Run Code Online (Sandbox Code Playgroud)

nmw*_*nmw 12

这里的关键部分是文档:

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

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


Ser*_*m's 7

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

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

所以我解决了:

public void setTextViewText(String text) {
    if (!this.textViewValue.getText().equals(text)) {
        this.textViewValue.setText(text);
    }
}
Run Code Online (Sandbox Code Playgroud)