Android自定义悬浮按钮,按钮可拖动,拖动结束后,按钮可自动靠边吸附。
下面是自定义View的详细代码。DragFloatActionButton继续ImageView,通过重写OnTouchEvent事件,实现View的拖动功能,当View被拖拽后,消耗掉事件,不响应点击事件。反之事件正常传递,响应按钮的OnClick事件。
左右吸附功能,DensityUtils.dp2px(getContext(), 20)是控制左右边距的大小,通过dp转化为px,适配不同分辨率的机型。如果需要靠边吸附,更改为0即可,如果不需要自动吸附功能,也直接注释掉就可以了,使用十分简单方便。
import android.animation.ObjectAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
import com.gainscha.uninstallapp.utils.DensityUtils;
/**
* FileName: DragButton
* Author: Administrators
* Time: 2019/2/23 9:34
* Desc: TODO
*/
public class DragFloatActionButton extends ImageView {
private static final String TAG = "DragButton";
private int parentHeight;
private int parentWidth;
private int lastX;
private int lastY;
private boolean isDrag;
private ViewGroup parent;
public DragFloatActionButton(Context context) {
super(context);
}
public DragFloatActionButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DragFloatActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int rawX = (int) event.getRawX();
int rawY = (int) event.getRawY();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
isDrag = false;
this.setAlpha(0.9f);
setPressed(true);
getParent().requestDisallowInterceptTouchEvent(true);
lastX = rawX;
lastY = rawY;
if (getParent() != null) {
parent = (ViewGroup) getParent();
parentHeight = parent.getHeight();
parentWidth = parent.getWidth();
}
break;
case MotionEvent.ACTION_MOVE:
this.setAlpha(0.9f);
int dx = rawX - lastX;
int dy = rawY - lastY;
int distance = (int) Math.sqrt(dx * dx + dy * dy);
if (distance > 2 && !isDrag) {
isDrag = true;
}
float x = getX() + dx;
float y = getY() + dy;
//检测是否到达边缘 左上右下
x = x < 0 ? 0 : x > parentWidth - getWidth() ? parentWidth - getWidth() : x;
y = getY() < 0 ? 0 : getY() + getHeight() > parentHeight ? parentHeight - getHeight() : y;
setX(x);
setY(y);
lastX = rawX;
lastY = rawY;
break;
case MotionEvent.ACTION_UP:
if (isDrag) {
//恢复按压效果
setPressed(false);
moveHide(rawX);
}
break;
}
//如果是拖拽则消耗事件,否则正常传递即可。
return isDrag || super.onTouchEvent(event);
}
private void moveHide(int rawX) {
if (rawX >= parentWidth / 2) {
//靠右吸附
animate().setInterpolator(new DecelerateInterpolator())
.setDuration(500)
//.xBy(parentWidth - getWidth() - getX())
.xBy(parentWidth - getWidth() - getX() - DensityUtils.dp2px(getContext(), 20))
.start();
} else {
//靠左吸附
//ObjectAnimator oa = ObjectAnimator.ofFloat(this, "x", getX(), 0);
ObjectAnimator oa = ObjectAnimator.ofFloat(this, "x", getX(),
DensityUtils.dp2px(getContext(), 20));
oa.setInterpolator(new DecelerateInterpolator());
oa.setDuration(500);
oa.start();
}
}
}