收到这个需求的时候第一想法是监听手指在屏幕中的操作,来实时获取手指所在屏幕的坐标,进行实时更新被拖动图的位置,但这种做法就会影响到页面中其它按钮的点击事件了。如果处理点击冲突事件,就记录被拖动图的区域再处理ontouch方法,这样就需要计算的成本很大了。

另外一种想法是,直接监听被拖动图的触摸事件,手指不停的移动,控件不停的改变位置,这种想法似乎更合理,只是要记录下最初位置,最后用平移动画要回去。思路整理清楚了,剩下就是代码的编写。

先处理的是onTouch方法:这里就是对被拖动控件的不断改变位置

@OverridepublicbooleanonTouch(Viewv,MotionEventevent){//如果长按拖动加上这句//if(!isLongClicked)returnfalse;switch(event.getAction()){caseMotionEvent.ACTION_MOVE:{//1.添加到Window中if(!dragDeleteView.isAttachedToWindow()){dragDeleteView.bindAnchorView(anchorView);wm.addView(dragDeleteView,params);v.getParent().requestDisallowInterceptTouchEvent(true);v.setVisibility(View.INVISIBLE);}//2.更新坐标位置dragDeleteView.updateFingerPoint(event.getRawX(),event.getRawY());break;}caseMotionEvent.ACTION_CANCEL:caseMotionEvent.ACTION_UP:{if(dragDeleteView.isOverThresholdHeight()){wm.removeView(dragDeleteView);callback.onDelete();}else{dragDeleteView.recover();}v.getParent().requestDisallowInterceptTouchEvent(false);isLongClicked=false;break;}}returnfalse;}

再需要的是判断是否超过了阈值,需要获取目标控件的区域,然后需要获取手指所在的x,y值,判断手指是否在目标区域。

/***判断是否拖拽超过了的阈值**@return*/publicbooleanisOverThresholdHeight(){finalint[]location=newint[2];dragDeleteView.getLocationOnScreen(location);//获得宽度intwidth=dragDeleteView.getMeasuredWidth();//获得高度intheight=dragDeleteView.getMeasuredHeight();floatimgY=mCurPoint.y+mAnchorBitmap.getHeight()*0.8f;floatimgX=mCurPoint.x+mAnchorBitmap.getWidth()*0.8f;if(imgX>(location[0])&&(imgX<location[0]+width)&&imgY>(location[1])&&imgY<(location[1]+height)){returntrue;}else{returnfalse;}}

最后就一个属性动画,如果拖动不在目标区域内,那么就回到原来位置,需要向前甩一定值后再回到原来位置。那么就需要用到插值器了,使用OvershootInterpolator就可以了。从手指抬起的位置到被拖动控件的初始位置。

/***供DragDeleteTouchPerformerInternal内部调用*<p>*恢复原先位置*/privatevoidrecover(){finalfloatdeltaX=mCurPoint.x-mStartPoint.x;finalfloatdeltaY=mCurPoint.y-mStartPoint.y;ValueAnimatoranim=ValueAnimator.ofFloat(1f,0f).setDuration(500);anim.setInterpolator(newOvershootInterpolator());anim.addUpdateListener(newValueAnimator.AnimatorUpdateListener(){@OverridepublicvoidonAnimationUpdate(ValueAnimatoranimation){mCurPoint.x=mStartPoint.x+deltaX*(float)animation.getAnimatedValue();mCurPoint.y=mStartPoint.y+deltaY*(float)animation.getAnimatedValue();invalidate();}});anim.addListener(newAnimatorListenerAdapter(){@OverridepublicvoidonAnimationEnd(Animatoranimation){mCallbackInternal.onRecovered();}});anim.start();}