Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

onMeasure custom view explanation

Tags:

android

view

I tried to do custom component. I extended View class and do some drawing in onDraw overrided method. Why I need to override onMeasure? If I didn't, everything seen to be right. May someone explain it? How should I write my onMeasure method? I've seen couple tutorials, but each one is a little bit different than the other. Sometimes they call super.onMeasure at the end, sometimes they use setMeasuredDimension and didn't call it. Where is a difference?

After all I want to use several exactly the same components. I added those components to my XML file, but I don't know how big they should be. I want to set its position and size later (why I need to set size in onMeasure if in onDraw when I draw it, is working as well) in custom component class. When exactly I need to do that?

like image 425
sennin Avatar asked Sep 04 '12 15:09

sennin


People also ask

How onMeasure works in Android?

onMeasure() is your opportunity to tell Android how big you want your custom view to be dependent the layout constraints provided by the parent; it is also your custom view's opportunity to learn what those layout constraints are (in case you want to behave differently in a match_parent situation than a wrap_content ...

What is a custom view in Android?

A well-designed custom view is much like any other well-designed class. It encapsulates a specific set of functionality with an easy to use interface, it uses CPU and memory efficiently, and so on. In addition to being a well-designed class, though, a custom view should: Conform to Android standards.

What is widthMeasureSpec?

Answer: widthMeasureSpec Horizontal space requirements as imposed by the parent view to the child view. heightMeasureSpec Vertical space requirements as imposed by the parent view to the child view. 2.


2 Answers

onMeasure() is your opportunity to tell Android how big you want your custom view to be dependent the layout constraints provided by the parent; it is also your custom view's opportunity to learn what those layout constraints are (in case you want to behave differently in a match_parent situation than a wrap_content situation). These constraints are packaged up into the MeasureSpec values that are passed into the method. Here is a rough correlation of the mode values:

  • EXACTLY means the layout_width or layout_height value was set to a specific value. You should probably make your view this size. This can also get triggered when match_parent is used, to set the size exactly to the parent view (this is layout dependent in the framework).
  • AT_MOST typically means the layout_width or layout_height value was set to match_parent or wrap_content where a maximum size is needed (this is layout dependent in the framework), and the size of the parent dimension is the value. You should not be any larger than this size.
  • UNSPECIFIED typically means the layout_width or layout_height value was set to wrap_content with no restrictions. You can be whatever size you would like. Some layouts also use this callback to figure out your desired size before determine what specs to actually pass you again in a second measure request.

The contract that exists with onMeasure() is that setMeasuredDimension() MUST be called at the end with the size you would like the view to be. This method is called by all the framework implementations, including the default implementation found in View, which is why it is safe to call super instead if that fits your use case.

Granted, because the framework does apply a default implementation, it may not be necessary for you to override this method, but you may see clipping in cases where the view space is smaller than your content if you do not, and if you lay out your custom view with wrap_content in both directions, your view may not show up at all because the framework doesn't know how large it is!

Generally, if you are overriding View and not another existing widget, it is probably a good idea to provide an implementation, even if it is as simple as something like this:

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {      int desiredWidth = 100;     int desiredHeight = 100;      int widthMode = MeasureSpec.getMode(widthMeasureSpec);     int widthSize = MeasureSpec.getSize(widthMeasureSpec);     int heightMode = MeasureSpec.getMode(heightMeasureSpec);     int heightSize = MeasureSpec.getSize(heightMeasureSpec);      int width;     int height;      //Measure Width     if (widthMode == MeasureSpec.EXACTLY) {         //Must be this size         width = widthSize;     } else if (widthMode == MeasureSpec.AT_MOST) {         //Can't be bigger than...         width = Math.min(desiredWidth, widthSize);     } else {         //Be whatever you want         width = desiredWidth;     }      //Measure Height     if (heightMode == MeasureSpec.EXACTLY) {         //Must be this size         height = heightSize;     } else if (heightMode == MeasureSpec.AT_MOST) {         //Can't be bigger than...         height = Math.min(desiredHeight, heightSize);     } else {         //Be whatever you want         height = desiredHeight;     }      //MUST CALL THIS     setMeasuredDimension(width, height); } 

Hope that Helps.

like image 171
devunwired Avatar answered Sep 21 '22 22:09

devunwired


actually, your answer is not complete as the values also depend on the wrapping container. In case of relative or linear layouts, the values behave like this:

  • EXACTLY match_parent is EXACTLY + size of the parent
  • AT_MOST wrap_content results in an AT_MOST MeasureSpec
  • UNSPECIFIED never triggered

In case of an horizontal scroll view, your code will work.

like image 25
Florian Avatar answered Sep 18 '22 22:09

Florian