/** * 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){// GONE的View暂时不进行测量measureChild(child,widthMeasureSpec,heightMeasureSpec);}}}
/** * 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=0;resultMode=MeasureSpec.UNSPECIFIED;}elseif(childDimension==LayoutParams.WRAP_CONTENT){// Child wants to determine its own size.... find out how// big it should beresultSize=0;resultMode=MeasureSpec.UNSPECIFIED;}break;}returnMeasureSpec.makeMeasureSpec(resultSize,resultMode);}
/** * <p> * This is called to find out how big a view should be. The parent * supplies constraint information in the width and height parameters. * </p> * * <p> * The actual measurement work of a view is performed in * {@link #onMeasure(int, int)}, called by this method. Therefore, only * {@link #onMeasure(int, int)} can and must be overridden by subclasses. * </p> * * * @param widthMeasureSpec Horizontal space requirements as imposed by the * parent * @param heightMeasureSpec Vertical space requirements as imposed by the * parent * * @see #onMeasure(int, int) */publicfinalvoidmeasure(intwidthMeasureSpec,intheightMeasureSpec){booleanoptical=isLayoutModeOptical(this);if(optical!=isLayoutModeOptical(mParent)){Insetsinsets=getOpticalInsets();intoWidth=insets.left+insets.right;intoHeight=insets.top+insets.bottom;widthMeasureSpec=MeasureSpec.adjust(widthMeasureSpec,optical?-oWidth:oWidth);heightMeasureSpec=MeasureSpec.adjust(heightMeasureSpec,optical?-oHeight:oHeight);}// Suppress sign extension for the low byteslongkey=(long)widthMeasureSpec<<32|(long)heightMeasureSpec&0xffffffffL;if(mMeasureCache==null)mMeasureCache=newLongSparseLongArray(2);if((mPrivateFlags&PFLAG_FORCE_LAYOUT)==PFLAG_FORCE_LAYOUT||widthMeasureSpec!=mOldWidthMeasureSpec||heightMeasureSpec!=mOldHeightMeasureSpec){// first clears the measured dimension flagmPrivateFlags&=~PFLAG_MEASURED_DIMENSION_SET;resolveRtlPropertiesIfNeeded();intcacheIndex=(mPrivateFlags&PFLAG_FORCE_LAYOUT)==PFLAG_FORCE_LAYOUT?-1:mMeasureCache.indexOfKey(key);if(cacheIndex<0||sIgnoreMeasureCache){// measure ourselves, this should set the measured dimension flag backonMeasure(widthMeasureSpec,heightMeasureSpec);mPrivateFlags3&=~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;}else{longvalue=mMeasureCache.valueAt(cacheIndex);// Casting a long to int drops the high 32 bits, no mask neededsetMeasuredDimensionRaw((int)(value>>32),(int)value);mPrivateFlags3|=PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;}// flag not set, setMeasuredDimension() was not invoked, we raise// an exception to warn the developerif((mPrivateFlags&PFLAG_MEASURED_DIMENSION_SET)!=PFLAG_MEASURED_DIMENSION_SET){thrownewIllegalStateException("onMeasure() did not set the"+" measured dimension by calling"+" setMeasuredDimension()");}mPrivateFlags|=PFLAG_LAYOUT_REQUIRED;}mOldWidthMeasureSpec=widthMeasureSpec;mOldHeightMeasureSpec=heightMeasureSpec;mMeasureCache.put(key,((long)mMeasuredWidth)<<32|(long)mMeasuredHeight&0xffffffffL);// suppress sign extension}
/** * <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 overriden 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));}
/** * <p>This method must be called by {@link #onMeasure(int, int)} to store the * measured width and measured height. Failing to do so will trigger an * exception at measurement time.</p> * * @param measuredWidth The measured width of this view. May be a complex * bit mask as defined by {@link #MEASURED_SIZE_MASK} and * {@link #MEASURED_STATE_TOO_SMALL}. * @param measuredHeight The measured height of this view. May be a complex * bit mask as defined by {@link #MEASURED_SIZE_MASK} and * {@link #MEASURED_STATE_TOO_SMALL}. */protectedfinalvoidsetMeasuredDimension(intmeasuredWidth,intmeasuredHeight){booleanoptical=isLayoutModeOptical(this);if(optical!=isLayoutModeOptical(mParent)){Insetsinsets=getOpticalInsets();intopticalWidth=insets.left+insets.right;intopticalHeight=insets.top+insets.bottom;measuredWidth+=optical?opticalWidth:-opticalWidth;measuredHeight+=optical?opticalHeight:-opticalHeight;}setMeasuredDimensionRaw(measuredWidth,measuredHeight);}
@OverrideprotectedvoidonLayout(booleanchanged,intl,intt,intr,intb){if(mOrientation==VERTICAL){layoutVertical(l,t,r,b);}else{layoutHorizontal(l,t,r,b);}}/** * Position the children during a layout pass if the orientation of this * LinearLayout is set to {@link #VERTICAL}. * * @see #getOrientation() * @see #setOrientation(int) * @see #onLayout(boolean, int, int, int, int) * @param left * @param top * @param right * @param bottom */voidlayoutVertical(intleft,inttop,intright,intbottom){finalintpaddingLeft=mPaddingLeft;intchildTop;intchildLeft;// Where right end of child should gofinalintwidth=right-left;intchildRight=width-mPaddingRight;// Space available for childintchildSpace=width-paddingLeft-mPaddingRight;finalintcount=getVirtualChildCount();finalintmajorGravity=mGravity&Gravity.VERTICAL_GRAVITY_MASK;finalintminorGravity=mGravity&Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;switch(majorGravity){caseGravity.BOTTOM:// mTotalLength contains the padding alreadychildTop=mPaddingTop+bottom-top-mTotalLength;break;// mTotalLength contains the padding alreadycaseGravity.CENTER_VERTICAL:childTop=mPaddingTop+(bottom-top-mTotalLength)/2;break;caseGravity.TOP:default:childTop=mPaddingTop;break;}for(inti=0;i<count;i++){finalViewchild=getVirtualChildAt(i);if(child==null){childTop+=measureNullChild(i);}elseif(child.getVisibility()!=GONE){finalintchildWidth=child.getMeasuredWidth();finalintchildHeight=child.getMeasuredHeight();finalLinearLayout.LayoutParamslp=(LinearLayout.LayoutParams)child.getLayoutParams();intgravity=lp.gravity;if(gravity<0){gravity=minorGravity;}finalintlayoutDirection=getLayoutDirection();finalintabsoluteGravity=Gravity.getAbsoluteGravity(gravity,layoutDirection);switch(absoluteGravity&Gravity.HORIZONTAL_GRAVITY_MASK){caseGravity.CENTER_HORIZONTAL:childLeft=paddingLeft+((childSpace-childWidth)/2)+lp.leftMargin-lp.rightMargin;break;caseGravity.RIGHT:childLeft=childRight-childWidth-lp.rightMargin;break;caseGravity.LEFT:default:childLeft=paddingLeft+lp.leftMargin;break;}if(hasDividerBeforeChildAt(i)){childTop+=mDividerHeight;}childTop+=lp.topMargin;setChildFrame(child,childLeft,childTop+getLocationOffset(child),childWidth,childHeight);childTop+=childHeight+lp.bottomMargin+getNextLocationOffset(child);i+=getChildrenSkipCount(child,i);}}}
/** * Manually render this view (and all of its children) to the given Canvas. * The view must have already done a full layout before this function is * called. When implementing a view, implement * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. * If you do need to override this method, call the superclass version. * * @param canvas The Canvas to which the View is rendered. */publicvoiddraw(Canvascanvas){finalintprivateFlags=mPrivateFlags;finalbooleandirtyOpaque=(privateFlags&PFLAG_DIRTY_MASK)==PFLAG_DIRTY_OPAQUE&&(mAttachInfo==null||!mAttachInfo.mIgnoreDirtyState);mPrivateFlags=(privateFlags&~PFLAG_DIRTY_MASK)|PFLAG_DRAWN;/* * Draw traversal performs several drawing steps which must be executed * in the appropriate order: * * 1. Draw the background * 2. If necessary, save the canvas' layers to prepare for fading * 3. Draw view's content * 4. Draw children * 5. If necessary, draw the fading edges and restore layers * 6. Draw decorations (scrollbars for instance) */// Step 1, draw the background, if neededintsaveCount;if(!dirtyOpaque){drawBackground(canvas);}// skip step 2 & 5 if possible (common case)finalintviewFlags=mViewFlags;booleanhorizontalEdges=(viewFlags&FADING_EDGE_HORIZONTAL)!=0;booleanverticalEdges=(viewFlags&FADING_EDGE_VERTICAL)!=0;if(!verticalEdges&&!horizontalEdges){// Step 3, draw the contentif(!dirtyOpaque)onDraw(canvas);// Step 4, draw the childrendispatchDraw(canvas);// Step 6, draw decorations (scrollbars)onDrawScrollBars(canvas);if(mOverlay!=null&&!mOverlay.isEmpty()){mOverlay.getOverlayView().dispatchDraw(canvas);}// we're done...return;}
/** * {@inheritDoc} */@OverrideprotectedvoiddispatchDraw(Canvascanvas){booleanusingRenderNodeProperties=canvas.isRecordingFor(mRenderNode);finalintchildrenCount=mChildrenCount;finalView[]children=mChildren;intflags=mGroupFlags;if((flags&FLAG_RUN_ANIMATION)!=0&&canAnimate()){finalbooleancache=(mGroupFlags&FLAG_ANIMATION_CACHE)==FLAG_ANIMATION_CACHE;finalbooleanbuildCache=!isHardwareAccelerated();for(inti=0;i<childrenCount;i++){finalViewchild=children[i];if((child.mViewFlags&VISIBILITY_MASK)==VISIBLE){finalLayoutParamsparams=child.getLayoutParams();attachLayoutAnimationParameters(child,params,i,childrenCount);bindLayoutAnimation(child);if(cache){child.setDrawingCacheEnabled(true);if(buildCache){child.buildDrawingCache(true);}}}}finalLayoutAnimationControllercontroller=mLayoutAnimationController;if(controller.willOverlap()){mGroupFlags|=FLAG_OPTIMIZE_INVALIDATE;}controller.start();mGroupFlags&=~FLAG_RUN_ANIMATION;mGroupFlags&=~FLAG_ANIMATION_DONE;if(cache){mGroupFlags|=FLAG_CHILDREN_DRAWN_WITH_CACHE;}if(mAnimationListener!=null){mAnimationListener.onAnimationStart(controller.getAnimation());}}intclipSaveCount=0;finalbooleanclipToPadding=(flags&CLIP_TO_PADDING_MASK)==CLIP_TO_PADDING_MASK;if(clipToPadding){clipSaveCount=canvas.save();canvas.clipRect(mScrollX+mPaddingLeft,mScrollY+mPaddingTop,mScrollX+mRight-mLeft-mPaddingRight,mScrollY+mBottom-mTop-mPaddingBottom);}// We will draw our child's animation, let's reset the flagmPrivateFlags&=~PFLAG_DRAW_ANIMATION;mGroupFlags&=~FLAG_INVALIDATE_REQUIRED;booleanmore=false;finallongdrawingTime=getDrawingTime();if(usingRenderNodeProperties)canvas.insertReorderBarrier();// Only use the preordered list if not HW accelerated, since the HW pipeline will do the// draw reordering internallyfinalArrayList<View>preorderedList=usingRenderNodeProperties?null:buildOrderedChildList();finalbooleancustomOrder=preorderedList==null&&isChildrenDrawingOrderEnabled();for(inti=0;i<childrenCount;i++){intchildIndex=customOrder?getChildDrawingOrder(childrenCount,i):i;finalViewchild=(preorderedList==null)?children[childIndex]:preorderedList.get(childIndex);if((child.mViewFlags&VISIBILITY_MASK)==VISIBLE||child.getAnimation()!=null){more|=drawChild(canvas,child,drawingTime);}}if(preorderedList!=null)preorderedList.clear();// Draw any disappearing views that have animationsif(mDisappearingChildren!=null){finalArrayList<View>disappearingChildren=mDisappearingChildren;finalintdisappearingCount=disappearingChildren.size()-1;// Go backwards -- we may delete as animations finishfor(inti=disappearingCount;i>=0;i--){finalViewchild=disappearingChildren.get(i);more|=drawChild(canvas,child,drawingTime);}}if(usingRenderNodeProperties)canvas.insertInorderBarrier();if(debugDraw()){onDebugDraw(canvas);}if(clipToPadding){canvas.restoreToCount(clipSaveCount);}// mGroupFlags might have been updated by drawChild()flags=mGroupFlags;if((flags&FLAG_INVALIDATE_REQUIRED)==FLAG_INVALIDATE_REQUIRED){invalidate(true);}if((flags&FLAG_ANIMATION_DONE)==0&&(flags&FLAG_NOTIFY_ANIMATION_LISTENER)==0&&mLayoutAnimationController.isDone()&&!more){// We want to erase the drawing cache and notify the listener after the// next frame is drawn because one extra invalidate() is caused by// drawChild() after the animation is overmGroupFlags|=FLAG_NOTIFY_ANIMATION_LISTENER;finalRunnableend=newRunnable(){publicvoidrun(){notifyAnimationListener();}};post(end);}}/** * Draw one child of this View Group. This method is responsible for getting * the canvas in the right state. This includes clipping, translating so * that the child's scrolled origin is at 0, 0, and applying any animation * transformations. * * @param canvas The canvas on which to draw the child * @param child Who to draw * @param drawingTime The time at which draw is occurring * @return True if an invalidate() was issued */protectedbooleandrawChild(Canvascanvas,Viewchild,longdrawingTime){returnchild.draw(canvas,this,drawingTime);}