Android实现炫酷的拖拽浮动按钮
IOS的Assistive Touch效果很炫酷,可以任意拖拽,同时点击后会展开菜单栏。然而,这不只是IOS的特权,Android也可以实现。但是由于悬浮窗需要申请权限,所以本文仅在app内实现,可以任意拖拽,并可以响应点击事件。
一、效果图

二、实现原理
1、拖拽实现
下面具体介绍重写onTouch方法的具体实现
case MotionEvent.ACTION_DOWN:{mDownPointerId = MotionEventCompat.getPointerId(event, 0);mPreviousX = event.getRawX();mPreviousY = event.getRawY();break;}
case MotionEvent.ACTION_MOVE:{if (mDownPointerId >= 0) {int index = MotionEventCompat.getActionIndex(event);int id = MotionEventCompat.getPointerId(event, index);if (id == mDownPointerId) {boolean update = adjustMarginParams(view, event);if (!update) {break;}mFloatView.requestLayout();mHasMoved = true;result = true;}}break;}
private boolean adjustMarginParams(View v, MotionEvent event) {float x = event.getRawX();float y = event.getRawY();float deltaX = x - mPreviousX;float deltaY = y - mPreviousY;if (!mHasMoved) {if (Math.abs(deltaX) < mTouchSlop && Math.abs(deltaY) < mTouchSlop) {return false;}}//左上角位置int newX = (int)x - mFloatView.getWidth() / 2;int newY = (int)y - mFloatView.getHeight() / 2;newX = Math.max(newX, mBoundsInScreen.left + mEdgePaddingLeft);newX = Math.min(newX, mBoundsInScreen.right - mEdgePaddingRight - mFloatView.getWidth());newY = Math.max(newY, mBoundsInScreen.top + mEdgePaddingTop);newY = Math.min(newY, mBoundsInScreen.bottom - mEdgePaddingBottom - mFloatView.getHeight());mFloatViewWindowParam.x = newX;mFloatViewWindowParam.y = newY - mParentMarginTop;return true;}
case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:{if (mDownPointerId >= 0 && mHasMoved) {event.setAction(MotionEvent.ACTION_CANCEL);adjustMarginParams(view, event);mFloatView.requestLayout();int center = (mBoundsInScreen.width() - mFloatView.getWidth()) / 2;int x = mFloatViewWindowParam.x;int destX = 0;int posX = Gravity.LEFT;//抬起时 根据位置强制把浮动按钮归于左边或右边if (x < center) { // 左边destX = mBoundsInScreen.left + mEdgePaddingLeft;} else {posX = Gravity.RIGHT;destX = mBoundsInScreen.right - mEdgePaddingRight - mFloatView.getWidth();}if (mFloatButtonCallback != null) {float posY = 0;if (mBoundsInScreen.height() - mFloatView.getHeight() != 0) {posY = 1f * (mFloatViewWindowParam.y - mBoundsInScreen.top) / (mBoundsInScreen.height() - mFloatView.getHeight());}mFloatButtonCallback.onPositionChanged(destX, mFloatViewWindowParam.y, posX, posY);}int deltaHorizon = destX - x;//小于100直接移动 否则开启动画if (Math.abs(deltaHorizon) < 100) {mFloatViewWindowParam.x = destX;mFloatView.requestLayout();} else {ValueAnimator animator = ValueAnimator.ofInt(x, destX);animator.setInterpolator(mInterpolator);if (mUpdateListener == null) {mUpdateListener = new FloatAnimatorUpdateListener();mUpdateListener.setUpdateView(FloatTouchListener.this);}animator.addUpdateListener(mUpdateListener);animator.setDuration(200);animator.start();}}resetStatus();break;}}
2、点击实现
public boolean onTouch(View view, MotionEvent event) {int action = MotionEventCompat.getActionMasked(event);if (mFloatButtonCallback != null) {mFloatButtonCallback.onTouch();}boolean result = false;switch (action) {case MotionEvent.ACTION_DOWN:{....................................................break;}case MotionEvent.ACTION_MOVE:{....................................................result = true;break;}case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:{................................................break;}}return result;}
原理就是这么简单,更加炫酷的效果可自定义实现
评论
