DrawerLayout源码分析
简介
DrawerLayout充当窗口内容的顶层容器,允许”抽屉”式的控件可以从窗口的一边或者两边垂直边缘拉出
使用
抽屉的位置或者布局可以通过Android:layout_gravity子view的属性控制从那边拉出,left/start代表从左边拉出,right/end代表从右侧拉出,需要注意的是只能有一个抽屉控件从窗口的垂直边缘,如果布局中每个垂直窗口有多于一个抽屉控件,将会抛出异常
根布局使用DrawerLayout作为第一个主内容布局,主内容布局宽高设置为match_parent不用设置layout_gravity,然后在主内容布局上添加子控件,并且设置layout_gravity
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawerlayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:id="@+id/fragment_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:id="@+id/left"
android:layout_width="200dp"
android:layout_height="match_parent"
android:layout_gravity="left"
android:background="@android:color/white">
android:id="@+id/left_listview"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:id="@+id/right"
android:layout_width="260dp"
android:layout_height="match_parent"
android:layout_gravity="right"
android:background="@android:color/holo_green_light">
android:id="@+id/right_textview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="个人登陆页面"/>
源码分析
构造函数
publicDrawerLayout(Contextcontext){
this(context,null);
}
publicDrawerLayout(Contextcontext,AttributeSetattrs){
this(context,attrs,0);
}
publicDrawerLayout(Contextcontext,AttributeSetattrs,intdefStyle){
super(context,attrs,defStyle);
setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
finalfloatdensity=getResources().getDisplayMetrics().density;
mMinDrawerMargin=(int)(MIN_DRAWER_MARGINdensity+0.5f);
finalfloatminVel=MIN_FLING_VELOCITYdensity;
mLeftCallback=newViewDragCallback(Gravity.LEFT);
mRightCallback=newViewDragCallback(Gravity.RIGHT);
mLeftDragger=ViewDragHelper.create(this,TOUCH_SLOP_SENSITIVITY,mLeftCallback);
mLeftDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
mLeftDragger.setMinVelocity(minVel);
mLeftCallback.setDragger(mLeftDragger);
mRightDragger=ViewDragHelper.create(this,TOUCH_SLOP_SENSITIVITY,mRightCallback);
mRightDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_RIGHT);
mRightDragger.setMinVelocity(minVel);
mRightCallback.setDragger(mRightDragger);
//Sothatwecancatchthebackbutton
setFocusableInTouchMode(true);
ViewCompat.setImportantForAccessibility(this,ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
ViewCompat.setAccessibilityDelegate(this,newAccessibilityDelegate());
ViewGroupCompat.setMotionEventSplittingEnabled(this,false);
if(ViewCompat.getFitsSystemWindows(this)){
IMPL.configureApplyInsets(this);
mStatusBarBackground=IMPL.getDefaultStatusBarBackground(context);
}
mDrawerElevation=DRAWER_ELEVATIONdensity;
mNonDrawerViews=newArrayList();
}
构造函数中,设置viewgroup的初始焦点,根据手机密度计算出Drawer的margin值,初始化从左侧边缘拉出来的布局的回掉监听和从右侧边缘拉出来的布局的回掉监听,其中,在DrawerLayout的源码是的滑动部分使用的是ViewDragHelper,所以要初始化左侧的滑动和右侧的滑动,设置触摸时的焦点,初始化view的List
ViewDragHelper的回调ViewDragCallback
其中初始化的过程中有个很重要的方法,就是ViewDragHelper的回掉,下面我们就来看一下ViewDragCallback
privateclassViewDragCallbackextendsViewDragHelper.Callback{
privatefinalintmAbsGravity;
privateViewDragHelpermDragger;
privatefinalRunnablemPeekRunable=newRunnable(){
@Overridepublicvoidrun(){
peekDrawer();
}
};
//注明拖拽的方向
publicViewDragCallback(intgravity){
mAbsGravity=gravity;
}
publicvoidsetDragger(ViewDragHelperdragger){
mDragger=dragger;
}
//移除方法回掉
publicvoidremoveCallbacks(){
DrawerLayout.this.removeCallbacks(mPeekRunnable);
}
//当前child是拖拽的view,并且当前拖拽是当前设置的方向,并且当前的child可以拖拽
@Override
publicbooleantryCaptureView(Viewchild,intpointerId){
//Onlycaptureviewswherethegravitymatcheswhatwe''relookingfor.
//ThisletsususetwoViewDragHelpers,oneforeachsidedrawer.
returnisDrawerView(child)&&checkDrawerViewAbsoluteGravity(child,mAbsGravity)&&getDrawerLockMode(child)==LOCK_MODE_UNLOCKED;
}
//当前拖拽的view的状态发生变化时,更新拖拽状态
@Override
publicvoidonViewDragStateChanged(intstate){
updateDrawerState(mAbsGravity,state,mDragger.getCapturedView());
}
//当view的位置发生变化时,重新布局
@Override
publicvoidonViewPositionChanged(ViewchangedView,intleft,inttop,intdx,intdy){
floatoffset;
finalintchildWidth=changedView.getWidth();
//ThisreversesthepositioningshowninonLayout.
if(checkDrawerViewAbsoluteGravity(changedView,Gravity.LEFT)){
offset=(float)(childWidth+left)/childWidth;
}else{
finalintwidth=getWidth();
offset=(float)(width-left)/childWidth;
}
setDrawerViewOffset(changedView,offset);
changedView.setVisibility(offset==0?INVISIBLE:VISIBLE);
invalidate();
}
//view开始被拖拽
@Override
publicvoidonViewCaptured(ViewcapturedChild,intactivePointerId){
finalLayoutParamslp=(LayoutParams)capturedChild.getLayoutParams();
lp.isPeeking=false;
closeOtherDrawer();
}
//确认当前拖拽的方向,关闭掉其他方向的拖拽
privatevoidcloseOtherDrawer(){
finalintotherGrav=mAbsGravity==Gravity.LEFT?Gravity.RIGHT:Gravity.LEFT;
finalViewtoClose=findDrawerWithGravity(otherGrav);
if(toClose!=null){
closeDrawer(toClose);
}
}
//被拖拽的被回掉时调用,先获得子view的宽,然后计算出左边距,滑动到指定位置
@Override
publicvoidonViewReleased(ViewreleasedChild,floatxvel,floatyvel){
//Offsetishowopenthedraweris,thereforeleft/rightvalues
//arereversedfromoneanother.
finalfloatoffset=getDrawerViewOffset(releasedChild);
finalintchildWidth=releasedChild.getWidth();
intleft;
if(checkDrawerViewAbsoluteGravity(releasedChild,Gravity.LEFT)){
left=xvel>0||xvel==0&&offset>0.5f?0:-childWidth;
}else{
finalintwidth=getWidth();
left=xvel<0||xvel==0&&offset>0.5f?width-childWidth:width;
}
mDragger.settleCapturedViewAt(left,releasedChild.getTop());
invalidate();
}
//触摸到边缘时回掉函数
@Override
publicvoidonEdgeTouched(intedgeFlags,intpointerId){
postDelayed(mPeekRunnable,PEEK_DELAY);
}
//根据拖拽的方向计算出view的左侧位置,判断是哪个方向滑动,如果是单侧划定关闭另一侧的view,取消另一侧的滑动
privatevoidpeekDrawer(){
finalViewtoCapture;
finalintchildLeft;
finalintpeekDistance=mDragger.getEdgeSize();
finalbooleanleftEdge=mAbsGravity==Gravity.LEFT;
if(leftEdge){
toCapture=findDrawerWithGravity(Gravity.LEFT);
childLeft=(toCapture!=null?-toCapture.getWidth():0)+peekDistance;
}else{
toCapture=findDrawerWithGravity(Gravity.RIGHT);
childLeft=getWidth()-peekDistance;
}
//Onlypeekifitwouldmeanmakingthedrawermorevisibleandthedrawerisn''tlocked
if(toCapture!=null&&((leftEdge&&toCapture.getLeft()childLeft))&&getDrawerLockMode(toCapture)==LOCK_MODE_UNLOCKED){
finalLayoutParamslp=(LayoutParams)toCapture.getLayoutParams();
mDragger.smoothSlideViewTo(toCapture,childLeft,toCapture.getTop());
lp.isPeeking=true;
invalidate();
closeOtherDrawer();
cancelChildViewTouch();
}
}
//是否锁定边缘,如果锁定边缘,view不为空并且view不能拖拽,关闭view的抽屉
@Override
publicbooleanonEdgeLock(intedgeFlags){
if(ALLOW_EDGE_LOCK){
finalViewdrawer=findDrawerWithGravity(mAbsGravity);
if(drawer!=null&&!isDrawerOpen(drawer)){
closeDrawer(drawer);
}
returntrue;
}
returnfalse;
}
//触摸边缘开始时调用此方法,先根据滑动方向获得当前view,如果当前view可以拖拽,捕获view的操作
@Override
publicvoidonEdgeDragStarted(intedgeFlags,intpointerId){
finalViewtoCapture;
if((edgeFlags&ViewDragHelper.EDGE_LEFT)==ViewDragHelper.EDGE_LEFT){
toCapture=findDrawerWithGravity(Gravity.LEFT);
}else{
toCapture=findDrawerWithGravity(Gravity.RIGHT);
}
if(toCapture!=null&&getDrawerLockMode(toCapture)==LOCK_MODE_UNLOCKED){
mDragger.captureChildView(toCapture,pointerId);
}
}
//获取拖拽view的水平方向的范围
@Override
publicintgetViewHorizontalDragRange(Viewchild){
returnisDrawerView(child)?child.getWidth():0;
}
//捕获水平方向的view被拖拽到的位置
@Override
publicintclampViewPositionHorizontal(Viewchild,intleft,intdx){
if(checkDrawerViewAbsoluteGravity(child,Gravity.LEFT)){
returnMath.max(-child.getWidth(),Math.min(left,0));
}else{
finalintwidth=getWidth();
returnMath.max(width-child.getWidth(),Math.min(left,width));
}
}
//垂直方向view移动的位置
@Override
publicintclampViewPositionVertical(Viewchild,inttop,intdy){
returnchild.getTop();
}
}
ViewDragHelper使用了Scroller,最后滑动的computeScroll()
@Override
publicvoidcomputeScroll(){
finalintchildCount=getChildCount();
floatscrimOpacity=0;
for(inti=0;i finalfloatonscreen=((LayoutParams)getChildAt(i).getLayoutParams()).onScreen;
scrimOpacity=Math.max(scrimOpacity,onscreen);
}
mScrimOpacity=scrimOpacity;
//"|"usedonpurpose;bothneedtorun.
if(mLeftDragger.continueSettling(true)|mRightDragger.continueSettling(true)){
ViewCompat.postInvalidateOnAnimation(this);
}
}
看过ViewDragHelper的人应该都知道上面这个方法中的含义,这里简单在代码中注释,详见ViewDragHelper源码分析
onInterceptTouchEvent方法
@Override
publicbooleanonInterceptTouchEvent(MotionEventev){
finalintaction=MotionEventCompat.getActionMasked(ev);
//"|"useddeliberatelyhere;bothmethodsshouldbeinvoked.
finalbooleaninterceptForDrag=mLeftDragger.shouldInterceptTouchEvent(ev)|mRightDragger.shouldInterceptTouchEvent(ev);
booleaninterceptForTap=false;
switch(action){
caseMotionEvent.ACTION_DOWN:{
finalfloatx=ev.getX();
finalfloaty=ev.getY();
mInitialMotionX=x;
mInitialMotionY=y;
if(mScrimOpacity>0){
finalViewchild=mLeftDragger.findTopChildUnder((int)x,(int)y);
if(child!=null&&isContentView(child)){
interceptForTap=true;
}
}
mDisallowInterceptRequested=false;
mChildrenCanceledTouch=false;
break;
}
caseMotionEvent.ACTION_MOVE:{
//Ifwecrossthetouchslop,don''tperformthedelayedpeekforanedgetouch.
if(mLeftDragger.checkTouchSlop(ViewDragHelper.DIRECTION_ALL)){
mLeftCallback.removeCallbacks();
mRightCallback.removeCallbacks();
}
break;
}
caseMotionEvent.ACTION_CANCEL:
caseMotionEvent.ACTION_UP:{
closeDrawers(true);
mDisallowInterceptRequested=false;
mChildrenCanceledTouch=false;
}
}
returninterceptForDrag||interceptForTap||hasPeekingDrawer()||mChildrenCanceledTouch;
在使用ViewDragHelper时都知道要拦截事件交给ViewDragHelper,还有几种情况也要拦截,如果左侧拖转的view不为空,并且gravity==Gravity.NO_GRAVITY也拦截该事件,在Down和Up也拦截该事件
privatebooleanhasPeekingDrawer(){
finalintchildCount=getChildCount();
for(inti=0;i finalLayoutParamslp=(LayoutParams)getChildAt(i).getLayoutParams();
if(lp.isPeeking){
returntrue;
}
}
returnfalse;
}
如果当前的子view是拖拽的view,也拦截该事件
onMeasure方法
由于DrawerLayout是继承自ViewGroup,所以onMeasure方法主要是计算本身的宽高和子view的宽高,处理设置wrap_content的情况
@Override
protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){
intwidthMode=MeasureSpec.getMode(widthMeasureSpec);
intheightMode=MeasureSpec.getMode(heightMeasureSpec);
intwidthSize=MeasureSpec.getSize(widthMeasureSpec);
intheightSize=MeasureSpec.getSize(heightMeasureSpec);
if(widthMode!=MeasureSpec.EXACTLY||heightMode!=MeasureSpec.EXACTLY){
if(isInEditMode()){
//Don''tcrashthelayouteditor.Consumeallofthespaceifspecified
//orpickamagicnumberfromthinairotherwise.
//TODOBettercommunicationwithtoolsofthisbogusstate.
//Itwillcrashonarealdevice.
if(widthMode==MeasureSpec.AT_MOST){
widthMode=MeasureSpec.EXACTLY;
}elseif(widthMode==MeasureSpec.UNSPECIFIED){
widthMode=MeasureSpec.EXACTLY;
widthSize=300;
}
if(heightMode==MeasureSpec.AT_MOST){
heightMode=MeasureSpec.EXACTLY;
}
elseif(heightMode==MeasureSpec.UNSPECIFIED){
heightMode=MeasureSpec.EXACTLY;
heightSize=300;
}
}else{
thrownewIllegalArgumentException("DrawerLayoutmustbemeasuredwithMeasureSpec.EXACTLY.");
}
}
setMeasuredDimension(widthSize,heightSize);
finalbooleanapplyInsets=mLastInsets!=null&&ViewCompat.getFitsSystemWindows(this);
finalintlayoutDirection=ViewCompat.getLayoutDirection(this);
//Onlyonedrawerispermittedalongeachverticaledge(left/right).Thesetwobooleans
//aretrackingthepresenceoftheedgedrawers.
booleanhasDrawerOnLeftEdge=false;
booleanhasDrawerOnRightEdge=false;
finalintchildCount=getChildCount();
for(inti=0;i finalViewchild=getChildAt(i);
if(child.getVisibility()==GONE){
continue;
}
finalLayoutParamslp=(LayoutParams)child.getLayoutParams();
if(applyInsets){
finalintcgrav=GravityCompat.getAbsoluteGravity(lp.gravity,layoutDirection);
if(ViewCompat.getFitsSystemWindows(child)){
IMPL.dispatchChildInsets(child,mLastInsets,cgrav);
}else{
IMPL.applyMarginInsets(lp,mLastInsets,cgrav);
}
}
if(isContentView(child)){
//Contentviewsgetmeasuredatexactlythelayout''ssize.
finalintcontentWidthSpec=MeasureSpec.makeMeasureSpec(widthSize-lp.leftMargin-lp.rightMargin,MeasureSpec.EXACTLY);
finalintcontentHeightSpec=MeasureSpec.makeMeasureSpec(heightSize-lp.topMargin-lp.bottomMargin,MeasureSpec.EXACTLY);
child.measure(contentWidthSpec,contentHeightSpec);
}elseif(isDrawerView(child)){
if(SET_DRAWER_SHADOW_FROM_ELEVATION){
if(ViewCompat.getElevation(child)!=mDrawerElevation){
ViewCompat.setElevation(child,mDrawerElevation);
}
}
final@EdgeGravityintchildGravity=getDrawerViewAbsoluteGravity(child)&Gravity.HORIZONTAL_GRAVITY_MASK;
//NotethattheisDrawerViewcheckguaranteesthatchildGravityhereiseither
//LEFTorRIGHT
booleanisLeftEdgeDrawer=(childGravity==Gravity.LEFT);
if((isLeftEdgeDrawer&&hasDrawerOnLeftEdge)||(!isLeftEdgeDrawer&&hasDrawerOnwww.baiyuewang.netRightEdge)){
thrownewIllegalStateException("Childdrawerhasabsolutegravity"+gravityToString(childGravity)+"butthis"+TAG+"alreadyhasa"+"drawerviewalongthatedge");
}
if(isLeftEdgeDrawer){
hasDrawerOnLeftEdge=true;
}else{
hasDrawerOnRightEdge=true;
}
finalintdrawerWidthSpec=getChildMeasureSpec(widthMeasureSpec,mMinDrawerMargin+lp.leftMargin+lp.rightMargin,lp.width);
finalintdrawerHeightSpec=getChildMeasureSpec(heightMeasureSpec,lp.topMargin+lp.bottomMargin,lp.height);
child.measure(drawerWidthSpec,drawerHeightSpec);
}else{
thrownewIllegalStateException("Child"+child+"atindex"+i+"doesnothaveavalidlayout_gravity-mustbeGravity.LEFT,"+"Gravity.RIGHTorGravity.NO_GRAVITY");
}
}
如果宽或者高不是MeasureSpec.EXACTLY时,如果widthMode等于MeasureSpec.AT_MOST
,则widthMode等于MeasureSpec.EXACTLY,如果widthMode等于MeasureSpec.UNSPECIFIED则宽默认等于300,高同理,然后遍历子view
booleanisContentView(Viewchild){
return((LayoutParams)child.getLayoutParams()).gravity==Gravity.NO_GRAVITY;
}
如果子view没有设置gravity属性的话,给子view设置宽高以及mode
booleanisDrawerView(Viewchild){
finalintgravity=((LayoutParams)child.getLayoutParams()).gravity;
finalintabsGravity=GravityCompat.getAbsoluteGravity(gravity,ViewCompat.getLayoutDirection(child));
if((absGravity&Gravity.LEFT)!=0){
//Thischildisaleft-edgedrawer
returntrue;
}
if((absGravity&Gravity.RIGHT)!=0){
//Thischildisaright-edgedrawer
returntrue;
}
returnfalse;
}
判断gravity属性是leftorright,然后通过child.measure(drawerWidthSpec,drawerHeightSpec);给子view设置宽高Spec
onLayout方法
@Override
protectedvoidonLayout(booleanchanged,intl,intt,intr,intb){
mInLayout=true;
finalintwidth=r-l;
finalintchildCount=getChildCount();
for(inti=0;i finalViewchild=getChildAt(i);
if(child.getVisibility()==GONE){
continue;
}
finalLayoutParamslp=(LayoutParams)child.getLayoutParams();
if(isContentView(child)){
child.layout(lp.leftMargin,lp.topMargin,lp.leftMargin+child.getMeasuredWidth(),lp.topMargin+child.getMeasuredHeight());
}else{//Drawer,ifitwasn''tonMeasurewouldhavethrownanexception.
finalintchildWidth=child.getMeasuredWidth();
finalintchildHeight=child.getMeasuredHeight();
intchildLeft;
finalfloatnewOffset;
if(checkDrawerViewAbsoluteGravity(child,Gravity.LEFT)){
childLeft=-childWidth+(int)(childWidthlp.onScreen);
newOffset=(float)(childWidth+childLeft)/childWidth;
}else{//Right;onMeasurecheckedforus.
childLeft=width-(int)(childWidthlp.onScreen);
newOffset=(float)(width-childLeft)/childWidth;
}
finalbooleanchangeOffset=newOffset!=lp.onScreen;
finalintvgrav=lp.gravity&Gravity.VERTICAL_GRAVITY_MASK;
switch(vgrav){
default:
caseGravity.TOP:{
child.layout(childLeft,lp.topMargin,childLeft+childWidth,lp.topMargin+childHeight);
break;
}
caseGravity.BOTTOM:{
finalintheight=b-t;
child.layout(childLeft,height-lp.bottomMargin-child.getMeasuredHeight(),childLeft+childWidth,height-lp.bottomMargin);
break;
}
caseGravity.CENTER_VERTICAL:{
finalintheight=b-t;
intchildTop=(height-childHeight)/2;
//Offsetformargins.Ifthingsdon''tfitrightbecauseof
//badmeasurementbefore,ohwell.
if(childTop childTop=lp.topMargin;
}elseif(childTop+childHeight>height-lp.bottomMargin){
childTop=height-lp.bottomMargin-childHeight;
}
child.layout(childLeft,childTop,childLeft+childWidth,childTop+childHeight);
break;
}
}
if(changeOffset){
setDrawerViewOffset(child,newOffset);
}
finalintnewVisibility=lp.onScreen>0?VISIBLE:INVISIBLE;
if(child.getVisibility()!=newVisibility){
child.setVisibility(newVisibility);
}
}
}
mInLayout=false;
mFirstLayout=false;
遍历子view,如果子view设置了gravity,根据子view的gravity属性计算childLeft和newOffset,如果子view是垂直方向的,根据gravity属性计算topandbottom
drawChild方法
@Override
protectedbooleandrawChild(Canvascanvas,Viewchild,longdrawingTime){
finalintheight=getHeight();
finalbooleandrawingContent=isContentView(child);
intclipLeft=0,clipRight=getWidth();
finalintrestoreCount=canvas.save();
if(drawingContent){
finalintchildCount=getChildCount();
for(inti=0;i finalViewv=getChildAt(i);
if(v==child||v.getVisibility()!=VISIBLE||!hasOpaqueBackground(v)||!isDrawerView(v)||v.getHeight() continue;
}
if(checkDrawerViewAbsoluteGravity(v,Gravity.LEFT)){
finalintvright=v.getRight();
if(vright>clipLeft)clipLeft=vright;
}else{
finalintvleft=v.getLeft();
if(vleft }
}
canvas.clipRect(clipLeft,0,clipRight,getHeight());
}
finalbooleanresult=super.drawChild(canvas,child,drawingTime);
canvas.restoreToCount(restoreCount);
if(mScrimOpacity>0&&drawingContent){
finalintbaseAlpha=(mScrimColor&0xff000000)>>>24;
finalintimag=(int)(baseAlphamScrimOpacity);
finalintcolor=imag<<24|(mScrimColor&0xffffff);
mScrimPaint.setColor(color);
canvas.drawRect(clipLeft,0,clipRight,getHeight(),mScrimPaint);
}elseif(mShadowLeftResolved!=null&&checkDrawerViewAbsoluteGravity(child,Gravity.LEFT)){
finalintshadowWidth=mShadowLeftResolved.getIntrinsicWidth();
finalintchildRight=child.getRight();
finalintdrawerPeekDistance=mLeftDragger.getEdgeSize();
finalfloatalpha=Math.max(0,Math.min((float)childRight/drawerPeekDistance,1.f));
mShadowLeftResolved.setBounds(childRight,child.getTop(),childRight+shadowWidth,child.getBottom());
mShadowLeftResolved.setAlpha((int)(0xffalpha));
mShadowLeftResowww.wang027.comlved.draw(canvas);
}elseif(mShadowRightResolved!=null&&checkDrawerViewAbsoluteGravity(child,Gravity.RIGHT)){
finalintshadowWidth=mShadowRightResolved.getIntrinsicWidth();
finalintchildLeft=child.getLeft();
finalintshowing=getWidth()-childLeft;
finalintdrawerPeekDistance=mRightDragger.getEdgeSize();
finalfloatalpha=Math.max(0,Math.min((float)showing/drawerPeekDistance,1.f));
mShadowRightResolved.setBounds(childLeft-shadowWidth,child.getTop(),childLeft,child.getBottom());
mShadowRightResolved.setAlpha((int)(0xffalpha));
mShadowRightResolved.draw(canvas);
}
returnresult;
}
判断当前的view是否设置gravity属性值,如果没有设置gravity,计算clipLeft和clipRight值,如果mScrimOpacity>0画一个矩形,如果view的gravity值为Gravity.LEFT,画右侧的view阴影部分,如果view的gravity值为Gravity.RIGHT画左侧的view阴影部分
DrawerLayout的主要功能就是滑动,源码中使用了ViewDragHelper实现了滑动,具体不了解的地方可以去看ViewDragHelper源码,DrawerLayout继承自ViewGroup,所以要去计算自身以及子view的宽高,以及实现子view在DrawerLayout的布局,本文主要描述主要的几个方法,想了解其他内容,自行查看源码
|
|