質問

My custom view is a slider, it follows the rules for onMeasure() when choosing the view height, when MeasureSpec is EXACTLY it sets the spec size, when it is UNSPECIFIED it sets a use defined size, when it is AT_MOST it chooses the minimum between them.

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int specHeight = Math.max(BOX_MIN_HEIGHT, 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); <<< BAD results
            //chosenHeight = specHeight; <<< GOOD results
        } else if( heightMode == MeasureSpec.EXACTLY ) {
            chosenHeight = specHeight;
        }

        setMeasuredDimension(specWidth, chosenHeight);

But this causes the view not to be drawn at all (onDraw() is not called)
If I uncomment the commented line for AT_MOST then the view is drawn.

The sliders are part of a LinearLayout containing 2 sliders and one View box, each one has the attribute layout_weight="1" set (see the images below).

Below I show you the good and bad logs and images (there are two sliders and 1 View below them):

GOOD:

enter image description here

BAD:

enter image description here

GOOD Log (see last lines, call to onDraw()):

03-26 08:06:10.288: D/AlphaSlider(9223): + onSizeChanged(w:579, h:58, oldw:0, oldh:0)
03-26 08:06:10.288: D/AlphaSlider(9223): + onLayout(changed:true, left:10, top:10, right:589, bottom:68)
03-26 08:06:10.288: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742360, heightMeasureSpec:1073742185)
03-26 08:06:10.288: W/AlphaSlider(9223): MeasureSpec EXACTLY, specSize=361, desiredSise=40, chosenSize=361
03-26 08:06:10.288: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742360, heightMeasureSpec:-2147483080)
03-26 08:06:10.288: W/AlphaSlider(9223): MeasureSpec AT_MOST, specSize=568, desiredSise=40, chosenSize=568
03-26 08:06:10.288: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742360, heightMeasureSpec:1073742000)
03-26 08:06:10.288: W/AlphaSlider(9223): MeasureSpec EXACTLY, specSize=176, desiredSise=40, chosenSize=176
03-26 08:06:10.288: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742360, heightMeasureSpec:1073742098)
03-26 08:06:10.288: W/AlphaSlider(9223): MeasureSpec EXACTLY, specSize=274, desiredSise=40, chosenSize=274
03-26 08:06:10.288: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742360, heightMeasureSpec:-2147483342)
03-26 08:06:10.288: W/AlphaSlider(9223): MeasureSpec AT_MOST, specSize=306, desiredSise=40, chosenSize=306
03-26 08:06:10.288: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742360, heightMeasureSpec:1073741913)
03-26 08:06:10.288: W/AlphaSlider(9223): MeasureSpec EXACTLY, specSize=89, desiredSise=40, chosenSize=89
03-26 08:06:10.288: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742360, heightMeasureSpec:1073742098)
03-26 08:06:10.288: W/AlphaSlider(9223): MeasureSpec EXACTLY, specSize=274, desiredSise=40, chosenSize=274
03-26 08:06:10.288: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742360, heightMeasureSpec:-2147483342)
03-26 08:06:10.288: W/AlphaSlider(9223): MeasureSpec AT_MOST, specSize=306, desiredSise=40, chosenSize=306
03-26 08:06:10.288: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742360, heightMeasureSpec:1073741913)
03-26 08:06:10.288: W/AlphaSlider(9223): MeasureSpec EXACTLY, specSize=89, desiredSise=40, chosenSize=89
03-26 08:06:10.288: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073742185)
03-26 08:06:10.288: W/AlphaSlider(9223): MeasureSpec EXACTLY, specSize=361, desiredSise=40, chosenSize=361
03-26 08:06:10.288: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:-2147483123)
03-26 08:06:10.288: W/AlphaSlider(9223): MeasureSpec AT_MOST, specSize=525, desiredSise=40, chosenSize=525
03-26 08:06:10.288: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073741986)
03-26 08:06:10.288: W/AlphaSlider(9223): MeasureSpec EXACTLY, specSize=162, desiredSise=40, chosenSize=162
03-26 08:06:10.288: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073742098)
03-26 08:06:10.288: W/AlphaSlider(9223): MeasureSpec EXACTLY, specSize=274, desiredSise=40, chosenSize=274
03-26 08:06:10.288: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:-2147483385)
03-26 08:06:10.288: W/AlphaSlider(9223): MeasureSpec AT_MOST, specSize=263, desiredSise=40, chosenSize=263
03-26 08:06:10.288: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073741898)
03-26 08:06:10.288: W/AlphaSlider(9223): MeasureSpec EXACTLY, specSize=74, desiredSise=40, chosenSize=74
03-26 08:06:10.315: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073742169)
03-26 08:06:10.315: W/AlphaSlider(9223): MeasureSpec EXACTLY, specSize=345, desiredSise=40, chosenSize=345
03-26 08:06:10.315: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:-2147483173)
03-26 08:06:10.315: W/AlphaSlider(9223): MeasureSpec AT_MOST, specSize=475, desiredSise=40, chosenSize=475
03-26 08:06:10.315: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073741969)
03-26 08:06:10.315: W/AlphaSlider(9223): MeasureSpec EXACTLY, specSize=145, desiredSise=40, chosenSize=145
03-26 08:06:10.315: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073742081)
03-26 08:06:10.315: W/AlphaSlider(9223): MeasureSpec EXACTLY, specSize=257, desiredSise=40, chosenSize=257
03-26 08:06:10.315: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:-2147483435)
03-26 08:06:10.315: W/AlphaSlider(9223): MeasureSpec AT_MOST, specSize=213, desiredSise=40, chosenSize=213
03-26 08:06:10.315: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073741882)
03-26 08:06:10.315: W/AlphaSlider(9223): MeasureSpec EXACTLY, specSize=58, desiredSise=40, chosenSize=58
03-26 08:06:10.315: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073742081)
03-26 08:06:10.315: W/AlphaSlider(9223): MeasureSpec EXACTLY, specSize=257, desiredSise=40, chosenSize=257
03-26 08:06:10.315: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:-2147483435)
03-26 08:06:10.315: W/AlphaSlider(9223): MeasureSpec AT_MOST, specSize=213, desiredSise=40, chosenSize=213
03-26 08:06:10.315: D/AlphaSlider(9223): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073741882)
03-26 08:06:10.315: W/AlphaSlider(9223): MeasureSpec EXACTLY, specSize=58, desiredSise=40, chosenSize=58
03-26 08:06:10.315: D/AlphaSlider(9223): + onLayout(changed:false, left:10, top:10, right:589, bottom:68)
03-26 08:06:10.323: D/AlphaSlider(9223): + onDraw()

BAD Log (no call to onDraw()):

03-26 07:43:33.453: D/AlphaSlider(8145): + onSizeChanged(w:579, h:30, oldw:0, oldh:0)  
03-26 07:43:33.463: D/AlphaSlider(8145): + onLayout(changed:true, left:10, top:10,right:589,bottom:40)  
03-26 07:43:33.463: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742360, heightMeasureSpec:1073742185)  
03-26 07:43:33.463: W/AlphaSlider(8145): MeasureSpec EXACTLY, specSize=361, desiredSise=40, chosenSize=361
03-26 07:43:33.473: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742360, heightMeasureSpec:-2147483080)
03-26 07:43:33.473: W/AlphaSlider(8145): MeasureSpec AT_MOST, specSize=568, desiredSise=40, chosenSize=40
03-26 07:43:33.473: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742360, heightMeasureSpec:1073741824)
03-26 07:43:33.473: W/AlphaSlider(8145): MeasureSpec EXACTLY, specSize=30, desiredSise=40, chosenSize=30
03-26 07:43:33.473: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742360, heightMeasureSpec:1073742098)
03-26 07:43:33.473: W/AlphaSlider(8145): MeasureSpec EXACTLY, specSize=274, desiredSise=40, chosenSize=274
03-26 07:43:33.473: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742360, heightMeasureSpec:-2147483342)
03-26 07:43:33.473: W/AlphaSlider(8145): MeasureSpec AT_MOST, specSize=306, desiredSise=40, chosenSize=40
03-26 07:43:33.473: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742360, heightMeasureSpec:1073741824)
03-26 07:43:33.473: W/AlphaSlider(8145): MeasureSpec EXACTLY, specSize=30, desiredSise=40, chosenSize=30
03-26 07:43:33.473: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742360, heightMeasureSpec:1073742098)
03-26 07:43:33.473: W/AlphaSlider(8145): MeasureSpec EXACTLY, specSize=274, desiredSise=40, chosenSize=274
03-26 07:43:33.473: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742360, heightMeasureSpec:-2147483342)
03-26 07:43:33.473: W/AlphaSlider(8145): MeasureSpec AT_MOST, specSize=306, desiredSise=40, chosenSize=40
03-26 07:43:33.473: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742360, heightMeasureSpec:1073741824)
03-26 07:43:33.473: W/AlphaSlider(8145): MeasureSpec EXACTLY, specSize=30, desiredSise=40, chosenSize=30
03-26 07:43:33.473: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073742185)
03-26 07:43:33.473: W/AlphaSlider(8145): MeasureSpec EXACTLY, specSize=361, desiredSise=40, chosenSize=361
03-26 07:43:33.473: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:-2147483123)
03-26 07:43:33.473: W/AlphaSlider(8145): MeasureSpec AT_MOST, specSize=525, desiredSise=40, chosenSize=40
03-26 07:43:33.473: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073741824)
03-26 07:43:33.473: W/AlphaSlider(8145): MeasureSpec EXACTLY, specSize=30, desiredSise=40, chosenSize=30
03-26 07:43:33.473: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073742098)
03-26 07:43:33.473: W/AlphaSlider(8145): MeasureSpec EXACTLY, specSize=274, desiredSise=40, chosenSize=274
03-26 07:43:33.473: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:-2147483385)
03-26 07:43:33.473: W/AlphaSlider(8145): MeasureSpec AT_MOST, specSize=263, desiredSise=40, chosenSize=40
03-26 07:43:33.473: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073741824)
03-26 07:43:33.473: W/AlphaSlider(8145): MeasureSpec EXACTLY, specSize=30, desiredSise=40, chosenSize=30
03-26 07:43:33.503: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073742169)
03-26 07:43:33.503: W/AlphaSlider(8145): MeasureSpec EXACTLY, specSize=345, desiredSise=40, chosenSize=345
03-26 07:43:33.503: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:-2147483173)
03-26 07:43:33.503: W/AlphaSlider(8145): MeasureSpec AT_MOST, specSize=475, desiredSise=40, chosenSize=40
03-26 07:43:33.503: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073741824)
03-26 07:43:33.503: W/AlphaSlider(8145): MeasureSpec EXACTLY, specSize=30, desiredSise=40, chosenSize=30
03-26 07:43:33.503: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073742081)
03-26 07:43:33.503: W/AlphaSlider(8145): MeasureSpec EXACTLY, specSize=257, desiredSise=40, chosenSize=257
03-26 07:43:33.503: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:-2147483435)
03-26 07:43:33.503: W/AlphaSlider(8145): MeasureSpec AT_MOST, specSize=213, desiredSise=40, chosenSize=40
03-26 07:43:33.503: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073741824)
03-26 07:43:33.503: W/AlphaSlider(8145): MeasureSpec EXACTLY, specSize=30, desiredSise=40, chosenSize=30
03-26 07:43:33.503: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073742081)
03-26 07:43:33.503: W/AlphaSlider(8145): MeasureSpec EXACTLY, specSize=257, desiredSise=40, chosenSize=257
03-26 07:43:33.503: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:-2147483435)
03-26 07:43:33.503: W/AlphaSlider(8145): MeasureSpec AT_MOST, specSize=213, desiredSise=40, chosenSize=40
03-26 07:43:33.503: D/AlphaSlider(8145): + onMeasure(widthMeasureSpec:1073742403, heightMeasureSpec:1073741824)
03-26 07:43:33.503: W/AlphaSlider(8145): MeasureSpec EXACTLY, specSize=30, desiredSise=40, chosenSize=30
03-26 07:43:33.503: D/AlphaSlider(8145): + onLayout(changed:false, left:10, top:10, right:589, bottom:40)
役に立ちましたか?

解決

Since I finally understood what's going on, I leave here the answer for future reference:

Android is doing what it has to do when measuring the UI components.
If the user (me in this case) does not follow the simple rules, then EXACTLY 0 may happen.
It can be made harmless if you just check for 0 size in the onSizeChanged() method. But even better if you avoid mixing measure modes, like I did. Explanation follows.

I defined in XML weighted views (using layout_weight). Those were the custom views mentioned in the question. My mistake was to also try to require a specific height for the views in

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

the culprit are the lines

int desiredHeight = Math.max(BOX_MIN_HEIGHT, HSVColorPickerPreference.this.boxHeight);

. . . 

    chosenHeight = Math.min(specHeight, desiredHeight);

. . .

This clashes head to head with the heuristic for weighted layout. Why? Let's take for example 3 widgets with weight=1, and one of them is behaving bad, as described above.

When LineraLayout makes a first pass over its children, it lets them get wild and ask for any size they want. In our example 2 widgets will ask for as much as possible, the custom widget will ask for something modest, less than the maximum.

The second pass is the killer, LinearLayout does not know one of the weighted widgets asked for less than it is supposed to, all in all, it has a weight defined for it. LinearLayout looks at the total requested measure form pass one and sees it is more than it has to give. Then it calculates the delta overflow and makes another pass distributing the overflow among the weighted widgets. Consequently the custom view widget has to cut back more than it requested, leaving it at 0 size.

The situation is analog to going for a beer with friends. You order one beer and your friends order beer, fries, chasers, the lot. At the end of the evening the check is split equally among everybody, you end up paying more than the beer you had. So did my custom view.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top