想要可浮动以及拖拽移动的菜单效果:没有做成更好的插件类型,只记录下关键过程。
1、FloatActionButton属于可浮动的按钮类型
2、自定义viewgroup存放FloatActionButton按钮以及实现拖拽移动效果
3、ValueAnimator 实现点击菜单动画效果
一、XML布局
<android.support.constraint.ConstraintLayout>
<ssq.com.myapp.Unit.FloatActionButtonMenuView
android:id="@+id/floatActionButtonMenuView"
android:layout_width="40dp"
android:layout_height="240dp"
android:layout_marginBottom="250dp"
android:layout_marginEnd="8dp"
android:clickable="true"
android:src="@drawable/float_button1"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<android.support.design.widget.FloatingActionButton
android:id="@+id/floatActionButton0"
app:elevation="0dp"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginTop="20dp"
android:src="@drawable/float_upload" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/floatActionButton1"
app:elevation="0dp"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginTop="20dp"
android:src="@drawable/float_button1" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/floatActionButton2"
app:elevation="0dp"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginTop="20dp"
android:src="@drawable/float_sub" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/floatActionButton3"
app:elevation="0dp"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginTop="20dp"
android:src="@drawable/float_menu" />
</ssq.com.myapp.Unit.FloatActionButtonMenuView>
</android.support.constraint.ConstraintLayout>
二、可拖拽效果关键函数
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;
getParent().requestDisallowInterceptTouchEvent(true);
lastX = rawX;
lastY = rawY;
// Log.e("down---->", "getX=" + getX() + ";screenWidthHalf=" + screenWidthHalf);
break;
case MotionEvent.ACTION_MOVE:
isDrag = true;
//计算手指移动了多少
int dx = rawX - lastX;
int dy = rawY - lastY;
//这里修复一些手机无法触发点击事件的问题
int distance= (int) Math.sqrt(dx*dx+dy*dy);
// Log.e("distance---->",distance+"");
if(distance<3){//给个容错范围,不然有部分手机还是无法点击
isDrag=false;
break;
}
float x = getX() + dx;
float y = getY() + dy;
//检测是否到达边缘 左上右下
x = x < 0 ? 0 : x > screenWidth - getWidth() ? screenWidth - getWidth() : x;
// y = y < statusHeight ? statusHeight : (y + getHeight() >= screenHeight ? screenHeight - getHeight() : y);
if (y<0){
y=0;
}
if (y>screenHeight-statusHeight-getHeight()){
y=screenHeight-statusHeight-getHeight();
}
setX(x);
setY(y);
lastX = rawX;
lastY = rawY;
// Log.e("move---->", "getX=" + getX() + ";screenWidthHalf=" + screenWidthHalf + " " + isDrag+" statusHeight="+statusHeight+ " virtualHeight"+virtualHeight+ " screenHeight"+ screenHeight+" getHeight="+getHeight()+" y"+y);
break;
case MotionEvent.ACTION_UP:
if (isDrag) {
//恢复按压效果
setPressed(false);
// Log.e("ACTION_UP---->", "getX=" + getX() + ";screenWidthHalf=" + screenWidthHalf);
if (rawX >= screenWidthHalf) {
animate().setInterpolator(new DecelerateInterpolator())
.setDuration(500)
.xBy(screenWidth - getWidth() - getX())
.start();
} else {
ObjectAnimator oa = ObjectAnimator.ofFloat(this, "x", getX(), 0);
oa.setInterpolator(new DecelerateInterpolator());
oa.setDuration(500);
oa.start();
}
}
// Log.e("up---->",isDrag+"");
break;
}
//如果是拖拽则消耗事件,否则正常传递即可。
return isDrag || super.onTouchEvent(event);
}
public boolean onInterceptTouchEvent(MotionEvent ev) { //拖拽跟点击事件拦截
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
break;
case MotionEvent.ACTION_MOVE: //必须要在MOVE中return才有效果,在这里return后UP事件也会被拦截
return true;
}
return super.onInterceptTouchEvent(ev);
}
三、ValueAnimator部分:(只实现在Y轴上菜单效果)list用于动态存放FloatActionButton按钮
private void ShowMenu(){
menuOpen = true;
if(list.size()==0)
return;
int y = (int) list.get(3).getY(); //标准参考位置
final FloatingActionButton f1=list.get(0);
final FloatingActionButton f2=list.get(1);
final FloatingActionButton f3=list.get(2);
ValueAnimator v1 = ValueAnimator.ofInt(y, y - DISTACE*3);//Y 轴方向移动distrace
v1.setDuration(500);
v1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int l = (int) f1.getX();
int t = (int) animation.getAnimatedValue();
int r = f1.getWidth()+l;
int b = f1.getHeight()+t;
f1.layout(l, t, r, b);
}
});
ValueAnimator v2y = ValueAnimator.ofInt(y, y - DISTACE*2);
v2y.setDuration(500).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int t = (int) animation.getAnimatedValue();
int l = (int) f2.getX();
int r = f2.getWidth() + l;
int b = f2.getHeight() + t;
f2.layout(l, t, r, b);
}
});
ValueAnimator v3 = ValueAnimator.ofInt(y, y - DISTACE*1); //起始位置主菜单y坐标,终位置向上移200
v3.setDuration(500).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int t = (int) animation.getAnimatedValue();
int l = (int) f3.getX();
int r = f3.getWidth() + l;
int b = f3.getHeight() + t;
f3.layout(l, t, r, b);
}
});
v1.start();
v2y.start();
v3.start();
}
private void hideMenu(){
menuOpen = false;
if(list.size()==0)
return;
FloatingActionButton menu=list.get(3);
final FloatingActionButton f1=list.get(0);
final FloatingActionButton f2=list.get(1);
final FloatingActionButton f3=list.get(2);
int y=(int)f1.getY();
ValueAnimator v1 = ValueAnimator.ofInt(y, (int) menu.getY());
v1.setDuration(500);
v1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int t = (int) animation.getAnimatedValue();
int l = (int) f1.getX();
int r = f1.getWidth() + l;
int b = f1.getHeight() + t;
f1.layout(l, t, r, b);
}
});
y=(int)f2.getY();
ValueAnimator v2y = ValueAnimator.ofInt(y, (int) menu.getY());
v2y.setDuration(500).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int t = (int) animation.getAnimatedValue();
int l = (int) f2.getX();
int r = f2.getWidth() + l;
int b = f2.getHeight() + t;
f2.layout(l, t, r, b);
}
});
y=(int)f3.getY();
ValueAnimator v3 = ValueAnimator.ofInt(y, (int) menu.getY());
v3.setDuration(500).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int t = (int) animation.getAnimatedValue();
int l = (int) f3.getX();
int r = f3.getWidth() + l;
int b = f3.getHeight() + t;
f3.layout(l, t, r, b);
}
});
v1.start();
v2y.start();
v3.start();
}