ilo*_*mbo 3 android android-custom-view android-layout
在调试自定义视图覆盖onMeasure()方法时,我看到有几次调用此方法.
我只处理视图的高度,保持宽度规格不变.
在某些时候,我接到一个调用(高度)MeasureSpec getMode()== EXACTLY和getSize()== 0.
这没有意义,并且与Android文档相矛盾:
Run Code Online (Sandbox Code Playgroud)MeasureSpecs are used to push requirements down the tree from parent to child. A MeasureSpec can be in one of three modes: UNSPECIFIED: This is used by a parent to determine the desired dimension of a child view. For example, a LinearLayout may call measure() on its child with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how tall the child view wants to be given a width of 240 pixels. EXACTLY: This is used by the parent to impose an exact size on the child. The child must use this size, and guarantee that all of its descendants will fit within this size. AT_MOST: This is used by the parent to impose a maximum size on the child. The child must guarantee that it and all of its descendants will fit within this size.
如果我这样做(孩子必须使用这个大小),setMeasureDimension(specWidth, sepcHeight)我得到一个异常,告诉视图的宽度和高度必须> 0.
我怀疑这个调用是由于在布局XML中,视图有layout_weight="1"和,根据到文档的建议:
要创建一个线性布局,其中每个孩子在屏幕上使用相同的空间量,请将每个视图的android:layout_height设置为"0dp"
但是,当MeasureSpec模式完全正确时,大小应该> 0.或者至少在这些情况下应该遵循一些规则,在文档中.
这是代码:
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int specHeight = MeasureSpec.getSize(heightMeasureSpec);
int specWidth = MeasureSpec.getSize(widthMeasureSpec);
int desiredHeight = Math.max(BOX_MIN_HEIGHT, HSVColorPickerPreference.this.boxHeight);
int chosenHeight = 0;
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if( heightMode == MeasureSpec.UNSPECIFIED ) {
chosenHeight = desiredHeight;
} else if( heightMode == MeasureSpec.AT_MOST ) {
chosenHeight = Math.min(specHeight, desiredHeight);
} else if( heightMode == MeasureSpec.EXACTLY ) {
chosenHeight = specHeight;
}
setMeasuredDimension(specWidth, chosenHeight);
Run Code Online (Sandbox Code Playgroud)
这是日志,请注意最后一次调用onMeasure():
03-29 08:17:13.388: D/ValueSlider(1384): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:-2147483435)
03-29 08:17:13.388: W/ValueSlider(1384): MeasureSpec AT_MOST, specSize=213, desiredSize=40, chosenSize=40
03-29 08:17:13.388: D/AlphaSlider(1384): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:-2147483435)
03-29 08:17:13.388: W/AlphaSlider(1384): MeasureSpec AT_MOST, specSize=213, desiredSize=40, chosenSize=40
03-29 08:17:13.388: D/ValueSlider(1384): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073741824)
03-29 08:17:13.388: W/ValueSlider(1384): MeasureSpec EXACTLY, specSize=0, desiredSize=40, chosenSize=0
03-29 08:17:13.388: D/AlphaSlider(1384): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073741824)
03-29 08:17:13.388: W/AlphaSlider(1384): MeasureSpec EXACTLY, specSize=0, desiredSize=40, chosenSize=0
03-29 08:17:13.508: D/ValueSlider(1384): + onSizeChanged(w:579, h:0, oldw:0, oldh:0)
03-29 08:17:13.508: D/AndroidRuntime(1384): Shutting down VM
03-29 08:17:13.508: W/dalvikvm(1384): threadid=1: thread exiting with uncaught exception (group=0xb2fe0180)
03-29 08:17:13.518: E/AndroidRuntime(1384): FATAL EXCEPTION: main
03-29 08:17:13.518: E/AndroidRuntime(1384): java.lang.IllegalArgumentException: width and height must be > 0
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.graphics.Bitmap.createBitmap(Bitmap.java:603)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.graphics.Bitmap.createBitmap(Bitmap.java:585)
03-29 08:17:13.518: E/AndroidRuntime(1384): at com.UturpatShuPepper.lib.HSVColorPickerPreference$Slider.onSizeChanged(HSVColorPickerPreference.java:962)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.View.setFrame(View.java:11361)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.View.layout(View.java:11272)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.View.layout(View.java:11278)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.ViewGroup.layout(ViewGroup.java:4224)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.widget.LinearLayout.onLayout(LinearLayout.java:1399)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.View.layout(View.java:11278)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.ViewGroup.layout(ViewGroup.java:4224)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.widget.RelativeLayout.onLayout(RelativeLayout.java:925)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.View.layout(View.java:11278)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.ViewGroup.layout(ViewGroup.java:4224)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.View.layout(View.java:11278)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.ViewGroup.layout(ViewGroup.java:4224)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.View.layout(View.java:11278)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.ViewGroup.layout(ViewGroup.java:4224)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.widget.LinearLayout.onLayout(LinearLayout.java:1399)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.View.layout(View.java:11278)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.ViewGroup.layout(ViewGroup.java:4224)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.View.layout(View.java:11278)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.ViewGroup.layout(ViewGroup.java:4224)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.View.layout(View.java:11278)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.ViewGroup.layout(ViewGroup.java:4224)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.View.layout(View.java:11278)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.ViewGroup.layout(ViewGroup.java:4224)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1489)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2442)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.os.Handler.dispatchMessage(Handler.java:99)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.os.Looper.loop(Looper.java:137)
03-29 08:17:13.518: E/AndroidRuntime(1384): at android.app.ActivityThread.main(ActivityThread.java:4424)
03-29 08:17:13.518: E/AndroidRuntime(1384): at java.lang.reflect.Method.invokeNative(Native Method)
03-29 08:17:13.518: E/AndroidRuntime(1384): at java.lang.reflect.Method.invoke(Method.java:511)
03-29 08:17:13.518: E/AndroidRuntime(1384): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
03-29 08:17:13.518: E/AndroidRuntime(1384): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
03-29 08:17:13.518: E/AndroidRuntime(1384): at dalvik.system.NativeStart.main(Native Method)
Run Code Online (Sandbox Code Playgroud)
由于我终于明白了发生了什么,我将在此留下答案以供将来参考:
在测量UI组件时,Android正在做它必须做的事情.
如果用户(在这种情况下我)不遵循简单规则,则可能会发生完全0.
如果你只是检查onSizeChanged()方法中的0大小,它可以变得无害.但是,如果你避免混合测量模式,就像我做的那样更好.说明如下.
我在XML加权视图中定义(使用layout_weight).这些是问题中提到的自定义视图.我的错误是也试图要求特定的视图高度
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
Run Code Online (Sandbox Code Playgroud)
罪魁祸首是线条
int desiredHeight = Math.max(BOX_MIN_HEIGHT, HSVColorPickerPreference.this.boxHeight);
. . .
chosenHeight = Math.min(specHeight, desiredHeight);
. . .
Run Code Online (Sandbox Code Playgroud)
这与加权布局的启发式发生冲突.为什么?让我们举例说明权重= 1的3个小部件,其中一个表现不好,如上所述.
当LineraLayout首次通过其子项时,它会让它们变得狂野并要求任何他们想要的大小.在我们的示例中,2个小部件将尽可能地要求,自定义小部件将要求适度的,小于最大值.
第二遍是杀手,LinearLayout不知道其中一个加权小部件要求的比它应该的少,总而言之,它有一个为它定义的权重.LinearLayout查看传递的总请求度量表单,并且看到它比它必须给出的更多.然后它计算delta溢出并进行另一次传递,在加权小部件之间分配溢出.因此,自定义视图小部件必须减少超过其请求的数量,使其保持0大小.
这种情况类似于和朋友一起去喝啤酒.你点了一杯啤酒,你的朋友点了啤酒,薯条,追逐者,这个地段.在晚上结束时,支票在每个人之间平均分配,最终支付的费用超过了你的啤酒.我的自定义视图也是如此.
| 归档时间: |
|
| 查看次数: |
1674 次 |
| 最近记录: |