I am using a FloatingActionButton in my app. Occasionally, it overlaps essential content, so I would like to make it so the user can drag the FAB out of the way.
No
All proposed answers used OnTouch listener, which is not recommended by recent Android API because of the Accessibility implementations. Note also that startDrag() method is obsolete. Developers shoud use startDragAndDrop() instead. My implementation uses OnDragListener() as follows:
Put the below snippet inside onCreatView() method, where root is root view, taken by the inflater (or any other view, which can receive Drop events);
final FloatingActionButton fab = root.findViewById(R.id.my_fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// Do whatever this button will do on click event
}
});
root.setOnDragListener(new View.OnDragListener() {
@Override
public boolean onDrag(View v, DragEvent event) {
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_LOCATION:
dX = event.getX();
dY = event.getY();
break;
case DragEvent.ACTION_DRAG_ENDED:
fab.setX(dX-fab.getWidth()/2);
fab.setY(dY-fab.getHeight()/2);
break;
}
return true;
}
});
fab.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
View.DragShadowBuilder myShadow = new View.DragShadowBuilder(fab);
v.startDragAndDrop(null, myShadow, null, View.DRAG_FLAG_GLOBAL);
return true;
}
});
You can try this code XML
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:id="@+id/dashboardShowActionsFab"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
JAVA
fab.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
int action = motionEvent.getAction();
if (action == MotionEvent.ACTION_DOWN) {
downRawX = motionEvent.getRawX();
downRawY = motionEvent.getRawY();
dX = view.getX() - downRawX;
dY = view.getY() - downRawY;
return true; // Consumed
} else if (action == MotionEvent.ACTION_MOVE) {
int viewWidth = view.getWidth();
int viewHeight = view.getHeight();
View viewParent = (View) view.getParent();
int parentWidth = viewParent.getWidth();
int parentHeight = viewParent.getHeight();
float newX = motionEvent.getRawX() + dX;
newX = Math.max(layoutParams.leftMargin, newX); // Don't allow the FAB past the left hand side of the parent
newX = Math.min(parentWidth - viewWidth - layoutParams.rightMargin, newX); // Don't allow the FAB past the right hand side of the parent
float newY = motionEvent.getRawY() + dY;
newY = Math.max(layoutParams.topMargin, newY); // Don't allow the FAB past the top of the parent
newY = Math.min(parentHeight - viewHeight - layoutParams.bottomMargin, newY); // Don't allow the FAB past the bottom of the parent
view.animate()
.x(newX)
.y(newY)
.setDuration(0)
.start();
return true; // Consumed
} else if (action == MotionEvent.ACTION_UP) {
float upRawX = motionEvent.getRawX();
float upRawY = motionEvent.getRawY();
float upDX = upRawX - downRawX;
float upDY = upRawY - downRawY;
if (Math.abs(upDX) < CLICK_DRAG_TOLERANCE && Math.abs(upDY) < CLICK_DRAG_TOLERANCE) { // A click
// return performClick();
Toast.makeText(MainActivity.this, "clicked", Toast.LENGTH_SHORT).show();
} else { // A drag
return true; // Consumed
}
} else {
//return super.onTouchEvent(motionEvent);
}
return true;
}
actually you can just use android.support.design.widget.CoordinatorLayout instead of Relative layout or any other layout and this will work(moving FAB)