自定义可拖拽悬浮Layout
float_button1.gif float_button2.gifDragFloatActionLayout.java
/**
* author: roc
* time: 2020-03-25 10:14
* explain: 可拖拽的悬浮View
*/
public class DragFloatActionLayout extends LinearLayout {
private Context mContext;
private int parentHeight;//父控件的高度
private int parentWidth;//父控件的宽度
private int lastX;
private int lastY;
private int downX = 0;
private int downY = 0;
private int upX = 0;
private int upY = 0;
private int borderMargin;//边界停留距离
private int stayTime;//停留时间
private float bottomMargin;//控件距离底部的距离
private float topMargin;//控件距离顶部的距离
private int remainWidth;//隐藏时边界剩余宽度
private boolean isBerth;//是否隐藏到边缘
private boolean isHide = false;//是否隐藏
private Timer mTimer;
private ViewGroup parent;
private OnClickListener onClickListener;
public DragFloatActionLayout(Context context) {
this(context, null);
}
public DragFloatActionLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DragFloatActionLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.DragFloatActionLayout, defStyleAttr, 0);
borderMargin = typedArray.getDimensionPixelSize(R.styleable.DragFloatActionLayout_base_float_action_border_margin, 0);
bottomMargin = typedArray.getDimensionPixelSize(R.styleable.DragFloatActionLayout_base_float_action_bottom_margin, DisplayUtil.dip2px(context, 50));
topMargin = typedArray.getDimensionPixelSize(R.styleable.DragFloatActionLayout_base_float_action_top_margin, DisplayUtil.dip2px(context, 50));
remainWidth = typedArray.getDimensionPixelSize(R.styleable.DragFloatActionLayout_base_float_action_remain_width, DisplayUtil.dip2px(context, 15));
stayTime = typedArray.getInteger(R.styleable.DragFloatActionLayout_base_float_action_stay_time, 5);
isBerth = typedArray.getBoolean(R.styleable.DragFloatActionLayout_base_float_action_is_berth, true);
typedArray.recycle();
}
@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:
if (mTimer != null) {//当手指按下时,应结束倒计时
mTimer.cancel();
mTimer = null;
}
ViewParent viewParent = getParent();
downX = lastX = rawX;
downY = lastY = rawY;
if (viewParent != null) {
//请求父控件不中断事件
viewParent.requestDisallowInterceptTouchEvent(true);
this.parent = (ViewGroup) viewParent;
//获取父控件的高度
parentHeight = this.parent.getHeight();
//获取父控件的宽度
parentWidth = this.parent.getWidth();
}
break;
case MotionEvent.ACTION_MOVE:
int dx = rawX - lastX;
int dy = rawY - lastY;
float x = getX() + dx;
float y = getY() + dy;
//检测是否到达边缘 左上右下
x = x < 0 ? 0 : x > parentWidth - getWidth() ? parentWidth - getWidth() : x;
//控件距离底部的margin
y = y < 0 ? 0 : (float) (y > parentHeight - getHeight() - bottomMargin ? parentHeight - getHeight() - bottomMargin :
(y < topMargin ? topMargin : y));
setX(x);
setY(y);
lastX = rawX;
lastY = rawY;
break;
case MotionEvent.ACTION_UP:
upX = (int) event.getRawX();
upY = (int) event.getRawY();
int distanceX = Math.abs(Math.abs(upX) - Math.abs(downX));
int distanceY = Math.abs(Math.abs(upY) - Math.abs(downY));
//当手指按下的事件跟手指抬起事件之间的距离小于10时执行点击事件
if (Math.max(distanceX, distanceY) <= 10) {
if (isHide) {
showView();
} else if (onClickListener != null) {
onClickListener.onClick();
}
} else {
moveHide(rawX);
}
if (isBerth)
hideView();//手指抬起n(n为自定义属性)秒后隐藏
break;
}
//如果是拖拽则消s耗事件,否则正常传递即可。
return true;
}
private void moveHide(int rawX) {
isHide = false;
if (rawX >= parentWidth / 2) {
//靠右吸附
animate().setInterpolator(new DecelerateInterpolator())
.setDuration(500)
.xBy(parentWidth - getWidth() - getX() - borderMargin)
.start();
} else {
//靠左吸附
ObjectAnimator oa = ObjectAnimator.ofFloat(this, "x", getX(), borderMargin);
oa.setInterpolator(new DecelerateInterpolator());
oa.setDuration(500);
oa.start();
}
}
/**
* 显示View
*/
private void showView() {
if (getX() >= parentWidth / 2) {//靠右显示
ObjectAnimator oa = ObjectAnimator.ofFloat(DragFloatActionLayout.this, "x", getX(), parentWidth - getWidth() - borderMargin);
oa.setInterpolator(new DecelerateInterpolator());
oa.setDuration(500);
oa.start();
} else {//靠左显示
ObjectAnimator oa = ObjectAnimator.ofFloat(DragFloatActionLayout.this, "x", getX(), borderMargin);
oa.setInterpolator(new DecelerateInterpolator());
oa.setDuration(500);
oa.start();
}
isHide = false;
}
/**
* 隐藏View
*/
private void hideView() {
if (mTimer == null)
mTimer = new Timer();
mTimer.schedule(new TimerTask() {
@Override
public void run() {
((Activity) mContext).runOnUiThread(new Runnable() {
@Override
public void run() {
if (getX() >= parentWidth / 2) {//靠右隐藏
ObjectAnimator oa = ObjectAnimator.ofFloat(DragFloatActionLayout.this, "x", getX(), parentWidth - remainWidth);
oa.setInterpolator(new DecelerateInterpolator());
oa.setDuration(500);
oa.start();
} else {//靠左隐藏
ObjectAnimator oa = ObjectAnimator.ofFloat(DragFloatActionLayout.this, "x", getX(), -getWidth() + remainWidth);
oa.setInterpolator(new DecelerateInterpolator());
oa.setDuration(500);
oa.start();
}
isHide = true;
}
});
}
}, stayTime * 1000);
}
/**
* 设置顶部距离
*
* @param topMargin
*/
public void setMarginTop(float topMargin) {
this.topMargin = topMargin;
}
public void setOnClickListener(OnClickListener onClickListener) {
this.onClickListener = onClickListener;
}
public interface OnClickListener {
void onClick();
}
/**
* 释放资源
*/
public void release() {
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
}
}
attr.xml
<!-- 自定义 可拖拽的悬浮View -->
<declare-styleable name="DragFloatActionLayout">
<attr name="base_float_action_border_margin" format="dimension" /><!-- 边界距离 -->
<attr name="base_float_action_bottom_margin" format="dimension" /><!-- 底部距离 -->
<attr name="base_float_action_top_margin" format="dimension" /><!-- 顶部距离 -->
<attr name="base_float_action_stay_time" format="integer" /><!-- 隐藏时间 -->
<attr name="base_float_action_remain_width" format="dimension" /><!-- 隐藏时边界露出的宽度 -->
<attr name="base_float_action_is_berth" format="boolean" /><!-- 是否停靠边缘隐藏 -->
</declare-styleable>
使用方式,像正常的Linearlayout
一样使用就行
<DragFloatActionLayout
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_above="@id/product_place_bottom_bar"
android:layout_alignParentEnd="true"
android:layout_marginEnd="15dp"
android:layout_marginBottom="40dp"
android:background="@drawable/consult_shape"
android:gravity="center"
android:orientation="vertical"
app:base_float_action_border_margin="15dp"
app:base_float_action_bottom_margin="50dp"
app:base_float_action_is_berth="false"
app:base_float_action_stay_time="5"
app:base_float_action_top_margin="200dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="center"
android:src="@mipmap/consult_img" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:gravity="center"
android:text="咨询"
android:textColor="@color/textColor3"
android:textSize="11sp" />
</DragFloatActionLayout>
网友评论