前言项目中只有一个UI,在页面底部上下拖动;今天我们就来讲解ViewDragHelper;这几天项目比较忙,文章更新会比较慢。提供了一系列非常有用的方法和状态跟踪,用于在ViewGroup中拖动和重新定位视图;1.ViewDragHelper初始化publicclassViewDragTestextendsLinearLayout{ViewDragHelpermViewDragHelper;@OverrideprotectedvoidonAttachedToWindow(){super.onAttachedToWindow();//中间参数表示敏感度,比如滑动了多少像素就认为触发了滑动。值越大,越敏感。mViewDragHelper=ViewDragHelper.create(this,1f,newDragCallback());}@OverridepublicbooleanonInterceptTouchEvent(MotionEventev){//修正写法intaction=MotionEventCompat.getActionMasked(ev);if(action==MotionEvent.ACTION_CANCEL||action==MotionEvent.ACTION_UP){mViewDragHelper.cancel();returnfalse;}returnmViewDragHelper.shouldInterceptTouchEvent(ev);}@OverridepublicbooleanonTouchEvent(MotionEventevent){//固定写法mViewDragHelper(TouchEvent(TouchEvent)event);returntrue;}@OverridepublicvoidcomputeScroll(){//固定写法//该方法用于自动滚动,比如自动滚动回默认位置。if(mViewDragHelper.continueSettling(true)){ViewCompat.postInvalidateOnAnimation(this);}}}2.ViewDragHelper.Callback//这个类的回调方法是ViewDragHelper的重点privateclassViewDragCallbackextendsViewDragHelper.Callback{@OverridepublicbooleantryCaptureView(Viewchild,intpointerId){//child表示要滑动的view//pointerId表示触摸点的id,比如多点按下的id//返回值表示是否可以捕捉,即是否可以滑动。可以根据不同的children判断是否可以滑动returntrue;}@OverridepublicintclampViewPositionHorizo??ntal(Viewchild,intleft,intdx){//child表示当前正在移动的view//left表示当前view即将移动到的地方左边距为left//dx表示距离上一张幻灯片的距离//返回值为child要移动的目标位置。可以控制返回值,这样child只能在ViewGroup的范围内移动。returnleft;}@OverridepublicintclampViewPositionVertical(Viewchild,inttop,intdy){//child表示当前正在移动的view//top表示当前view即将移动到上边距top的地方//dx表示距离从上一张幻灯片returntop;}}重写上面3个方法,就可以正常工作了。子View可以任意拖动;3.控制child在父view中的移动范围//控制child在ViewGroup中只能水平移动@OverridepublicintclampViewPositionHorizo??ntal(Viewchild,intleft,intdx){finalintleftBound=getPaddingLeft();finalintrightBound=getWidth()-mDragView.getWidth();finalintnewLeft=Math.min(Math.max(left,leftBound),rightBound);returnnewLeft;}//控件child只能在ViewGroup的垂直方向移动@OverridepublicintclampViewPositionVertical(Viewchild,inttop,intdy){finalinttopBound=getPaddingTop();finalintbottomBound=getHeight()-mDragView.getHeight();finalintnewTop=Math.min(Math.max(top,topBound),bottomBound;returnnewTop;}4.启用边框滑动//启用4边mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_ALL);//每边publicstaticfinalintEDGE_LEFT=1<<0;publicstaticfinalintEDGE_RIGHT=1<<1;publicstaticfinalintEDGE_TOP=1<<2;publicstaticfinalintEDGE_BOTTOM=1<<3;//启用边框滑动时,该方法会回调@OverridepublicvoidonEdgeTouched(intedgeFlags,intpointerId){//通常启用边框后,需要手动抓取视图。然后你可以滑动视图。mViewDragHelper.captureChildView(getChildAt(1),pointerId);}@OverridepublicbooleantryCaptureView(Viewchild,intpointerId){//打开边框后,该方法的返回值可能需要进一步处理。否则,开放边境是没有意义的。returnfalse;}5.释放后的回弹效果有时候释放的时候需要让View回到原来的位置;//释放的时候会回调下面的方法@OverridepublicvoidonViewReleased(ViewreleasedChild,floatxvel,floatyvel){//调用该方法,可以设置releasedChild反弹位置.mViewDragHelper.settleCapturedViewAt(0,100);//参数为x,y坐标postInvalidate();//注意必须调用此方法,否则没有效果}//下面两个方法最后调用forceSettleCapturedViewAt().mViewDragHelper.settleCapturedViewAt(0,100);mViewDragHelper.smoothSlideViewTo(getChildAt(1),0,100);//所以...发挥你的想象力,看看有什么用!!!//如果你没有忘记...上一篇文章应该说涉及到scroll的时候view的这个方法需要重写//这个方法必须重写,否则没有效果@OverridepublicvoidcomputeScroll(){//固定写法if(mViewDragHelper.continueSettling(true)){postInvalidate();//这里要注意}}通过上面两个方法的设置,当手指松开时,View会自动滑动到指定位置...(不是一下子全部滑到指定位置,有一个滑动过程。)注意:如果需要滑动View,会consu我的touch事件,比如:Button,那么就需要重写下面的方法。@OverridepublicintgetViewHorizo??ntalDragRange(Viewchild){returnchild.getMeasuredWidth();//返回一个大于0的值即可}@OverridepublicintgetViewVerticalDragRange(Viewchild){returnchild.getMeasuredHeight();//返回一个大于0的值即可}6.简单的api介绍ViewDragHelper的APIViewDragHelpercreate(ViewGroupforParent,Callbackcb);静态创建方法,参数1:入口和出口对应ViewGroup参数2:回调shouldInterceptTouchEvent(MotionEventev)处理事件分发(主要分发ViewGroup事件委托给ViewDragHelper用于处理)参数1:MotionEventev主要是处理对应TouchEvent的ViewGroup事件processTouchEvent(MotionEventevent)方法,这里需要注意一个问题,在处理对应的TouchEvent时,返回结果为true,并且这个活动应该消费!否则你将无法使用ViewDragHelper来处理相应的拖动事件!APItryCaptureView(Viewchild,intpointerId)的ViewDragHelper.Callback这个是抽象类,必须实现,后面的方法只有在这个方法返回true时才会生效;参数1:捕获的View(也就是你拖拽的View)onViewDragStateChanged(intstate)状态改变时回调,返回相应的状态(这里有三种状态)STATE_IDLE空闲状态STATE_DRAGGING正在拖拽STATE_SETTLING到某个位置onViewPositionChanged(ViewchangedView,intleft,inttop,intdx,intdy)当你拖动的View位置发生变化时回调。参数1:当前拖动的View参数2:距离左边的距离参数3:距离右边的距离参数4:x轴的变化参数5:y轴的变化onViewCaptured(ViewcapturedChild,intactivePointerId)调用的方法当View被捕获时参数1:被捕获的View(也就是你拖动的View)onViewReleased(ViewreleasedChild,floatxvel,floatyvel)当View停止拖动时调用的方法。一般在这个方法中会重新设置一些参数,比如回弹。参数1:你拖动的View参数2:x轴的速度参数3:y轴的速度clampViewPositionVertical(Viewchild,inttop,intdy)垂直拖动时的回调方法参数1:被拖动的View参数2:距离顶端参数3:VariationclampViewPositionHorizo??ntal(Viewchild,intleft,intdx)水平拖动时的回调方法参数1:拖动View参数2:距离左边的距离参数3:Variation2.简单实现demo下面是一个简单实现的demo,可以直接复制使用的1、BottomView的ViewDragHelper实现publicclassBottomViewextendsLinearLayout{privateViewDragHelpermDragHelper;privateViewview;privateintmDragBorder,verticalRange,mDragState,peekHeight,mDragHeight;privatefinaldoubleAUTO_OPEN_SPEED_LIMIT=800.0;privatebooleaninflate=false,isExpanded=false,isDragHeightSet=false;privateMotionEventglobalEvent;Viewtry_view;publicBottomView(Contextcontext){super(context);}publicBottomView(Contextcontext,@NullableAttributeSetattrs){super(context,attrs);initView(context,attrs);}publicBottomView(Contextcontext,@NullableAttributeSetattrs,intdefStyleAttr){super(context,attrs,defStyleAttr);initView(context,attrs);}voidinitView(Contextcontext,AttributeSetattrs){peekHeight=300;}@OverrideprotectedvoidonAttachedToWindow(){super.onAttachedToWindow();}@OverrideprotectedvoidonFinishInflate(){super.onFinishInflate();mDragHelper=ViewDragHelper.create(this,1.0f,newDragHelperCallback());view=getChildAt(0);try_view=findViewById(R.id.ll_try_view);}@OverrideprotectedvoidonLayout(booleanb,intleft,inttop,intright,intbottom){verticalRange=getMeasuredHeight()-peekHeight;if(!inflate){mDragBorder=verticalRange;inflate=true;}view.layout(left,mDragBorder,right,bottom+mDragBorder);}@OverridepublicbooleanonInterceptTouchEvent(MotionEventev){intaction=MotionEventCompat.getActionMasked(ev);if((action==MotionEvent.ACTION_CANCEL||action==MotionEvent.ACTION_UP)&&!isDraggingAllowed(ev)){mDragHelper.cancel();returnfalse;}returnmDragHelper.shouldInterceptTouchEvent(ev);}@OverridepublicbooleanonTouchEvent(MotionEventevent){if(isDraggingAllowed(event)||isMoving()){mDragHelper.processTouchEvent(event);returntrue;}returnsuper.onTouchEvent(event);}@OverridepublicbooleandispatchTouchEvent(MotionEventev){globalEvent=ev;returnsuper.dispatchTouchEvent(ev);}嘘leanisDraggingAllowed(MotionEventevent){int[]viewLocations=newint[2];view.getLocationOnScreen(viewLocations);intupperLimit=viewLocations[1]+(isDragHeightSet?mDragHeight:peekHeight);intlowerLimit=viewLocations[1];inty=(int)事件.getRawY();return(y>lowerLimit&&y
