/** * <p> * Measure the view and its content to determine the measured width and the * measured height. This method is invoked by {@link #measure(int, int)} and * should be overridden by subclasses to provide accurate and efficient * measurement of their contents. * </p> * * <p> * <strong>CONTRACT:</strong> When overriding this method, you * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the * measured width and height of this view. Failure to do so will trigger an * <code>IllegalStateException</code>, thrown by * {@link #measure(int, int)}. Calling the superclass' * {@link #onMeasure(int, int)} is a valid use. * </p> * * <p> * The base class implementation of measure defaults to the background size, * unless a larger size is allowed by the MeasureSpec. Subclasses should * override {@link #onMeasure(int, int)} to provide better measurements of * their content. * </p> * * <p> * If this method is overridden, it is the subclass's responsibility to make * sure the measured height and width are at least the view's minimum height * and width ({@link #getSuggestedMinimumHeight()} and * {@link #getSuggestedMinimumWidth()}). * </p> * * @param widthMeasureSpec horizontal space requirements as imposed by the parent. * The requirements are encoded with * {@link android.view.View.MeasureSpec}. * @param heightMeasureSpec vertical space requirements as imposed by the parent. * The requirements are encoded with * {@link android.view.View.MeasureSpec}. * * @see #getMeasuredWidth() * @see #getMeasuredHeight() * @see #setMeasuredDimension(int, int) * @see #getSuggestedMinimumHeight() * @see #getSuggestedMinimumWidth() * @see android.view.View.MeasureSpec#getMode(int) * @see android.view.View.MeasureSpec#getSize(int) */protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(),widthMeasureSpec),getDefaultSize(getSuggestedMinimumHeight(),heightMeasureSpec));}/** * Utility to return a default size. Uses the supplied size if the * MeasureSpec imposed no constraints. Will get larger if allowed * by the MeasureSpec. * * @param size Default size for this view * @param measureSpec Constraints imposed by the parent * @return The size this view should be. */publicstaticintgetDefaultSize(intsize,intmeasureSpec){intresult=size;intspecMode=MeasureSpec.getMode(measureSpec);intspecSize=MeasureSpec.getSize(measureSpec);switch(specMode){caseMeasureSpec.UNSPECIFIED:result=size;break;caseMeasureSpec.AT_MOST:caseMeasureSpec.EXACTLY:result=specSize;break;}returnresult;}/** * Returns the suggested minimum width that the view should use. This * returns the maximum of the view's minimum width * and the background's minimum width * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). * <p> * When being used in {@link #onMeasure(int, int)}, the caller should still * ensure the returned width is within the requirements of the parent. * * @return The suggested minimum width of the view. */protectedintgetSuggestedMinimumWidth(){return(mBackground==null)?mMinWidth:max(mMinWidth,mBackground.getMinimumWidth());}
/** * Ask all of the children of this view to measure themselves, taking into * account both the MeasureSpec requirements for this view and its padding. * We skip children that are in the GONE state The heavy lifting is done in * getChildMeasureSpec. * * @param widthMeasureSpec The width requirements for this view * @param heightMeasureSpec The height requirements for this view */protectedvoidmeasureChildren(intwidthMeasureSpec,intheightMeasureSpec){finalintsize=mChildrenCount;finalView[]children=mChildren;for(inti=0;i<size;++i){finalViewchild=children[i];if((child.mViewFlags&VISIBILITY_MASK)!=GONE){measureChild(child,widthMeasureSpec,heightMeasureSpec);}}}/** * Ask one of the children of this view to measure itself, taking into * account both the MeasureSpec requirements for this view and its padding. * The heavy lifting is done in getChildMeasureSpec. * * @param child The child to measure * @param parentWidthMeasureSpec The width requirements for this view * @param parentHeightMeasureSpec The height requirements for this view */protectedvoidmeasureChild(Viewchild,intparentWidthMeasureSpec,intparentHeightMeasureSpec){finalLayoutParamslp=child.getLayoutParams();finalintchildWidthMeasureSpec=getChildMeasureSpec(parentWidthMeasureSpec,mPaddingLeft+mPaddingRight,lp.width);finalintchildHeightMeasureSpec=getChildMeasureSpec(parentHeightMeasureSpec,mPaddingTop+mPaddingBottom,lp.height);child.measure(childWidthMeasureSpec,childHeightMeasureSpec);}/** * Does the hard part of measureChildren: figuring out the MeasureSpec to * pass to a particular child. This method figures out the right MeasureSpec * for one dimension (height or width) of one child view. * * The goal is to combine information from our MeasureSpec with the * LayoutParams of the child to get the best possible results. For example, * if the this view knows its size (because its MeasureSpec has a mode of * EXACTLY), and the child has indicated in its LayoutParams that it wants * to be the same size as the parent, the parent should ask the child to * layout given an exact size. * * @param spec The requirements for this view * @param padding The padding of this view for the current dimension and * margins, if applicable * @param childDimension How big the child wants to be in the current * dimension * @return a MeasureSpec integer for the child */publicstaticintgetChildMeasureSpec(intspec,intpadding,intchildDimension){intspecMode=MeasureSpec.getMode(spec);intspecSize=MeasureSpec.getSize(spec);intsize=Math.max(0,specSize-padding);intresultSize=0;intresultMode=0;switch(specMode){// Parent has imposed an exact size on uscaseMeasureSpec.EXACTLY:if(childDimension>=0){resultSize=childDimension;resultMode=MeasureSpec.EXACTLY;}elseif(childDimension==LayoutParams.MATCH_PARENT){// Child wants to be our size. So be it.resultSize=size;resultMode=MeasureSpec.EXACTLY;}elseif(childDimension==LayoutParams.WRAP_CONTENT){// Child wants to determine its own size. It can't be// bigger than us.resultSize=size;resultMode=MeasureSpec.AT_MOST;}break;// Parent has imposed a maximum size on uscaseMeasureSpec.AT_MOST:if(childDimension>=0){// Child wants a specific size... so be itresultSize=childDimension;resultMode=MeasureSpec.EXACTLY;}elseif(childDimension==LayoutParams.MATCH_PARENT){// Child wants to be our size, but our size is not fixed.// Constrain child to not be bigger than us.resultSize=size;resultMode=MeasureSpec.AT_MOST;}elseif(childDimension==LayoutParams.WRAP_CONTENT){// Child wants to determine its own size. It can't be// bigger than us.resultSize=size;resultMode=MeasureSpec.AT_MOST;}break;// Parent asked to see how big we want to becaseMeasureSpec.UNSPECIFIED:if(childDimension>=0){// Child wants a specific size... let him have itresultSize=childDimension;resultMode=MeasureSpec.EXACTLY;}elseif(childDimension==LayoutParams.MATCH_PARENT){// Child wants to be our size... find out how big it should// beresultSize=View.sUseZeroUnspecifiedMeasureSpec?0:size;resultMode=MeasureSpec.UNSPECIFIED;}elseif(childDimension==LayoutParams.WRAP_CONTENT){// Child wants to determine its own size.... find out how// big it should beresultSize=View.sUseZeroUnspecifiedMeasureSpec?0:size;resultMode=MeasureSpec.UNSPECIFIED;}break;}//noinspection ResourceTypereturnMeasureSpec.makeMeasureSpec(resultSize,resultMode);}