Android - 可移动/可拖动浮动按钮(FAB)
问题描述:
我在我的应用中使用了FloatingActionButton。偶尔,它与重要内容重叠,所以我想这样做,以便用户可以将FAB拖出。Android - 可移动/可拖动浮动按钮(FAB)
本身不需要拖放功能。它只是需要移动。文档没有提到这一点,但我相信我在其他应用中看到过这样的功能。
你能建议/提供一个关于如何做的代码片段(最好是XML)。
答
基于this answer for another SO question这是我的代码创建。这似乎是(有工作点击功能)很好地工作,而不是依赖于FAB的父布局或定位...
package com.example;
import android.content.Context;
import android.support.design.widget.FloatingActionButton;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class MovableFloatingActionButton extends FloatingActionButton implements View.OnTouchListener {
private final static float CLICK_DRAG_TOLERANCE = 10; // Often, there will be a slight, unintentional, drag when the user taps the FAB, so we need to account for this.
private float downRawX, downRawY;
private float dX, dY;
public MovableFloatingActionButton(Context context) {
super(context);
init();
}
public MovableFloatingActionButton(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MovableFloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setOnTouchListener(this);
}
@Override
public boolean onTouch(View view, MotionEvent motionEvent){
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(0, newX); // Don't allow the FAB past the left hand side of the parent
newX = Math.min(parentWidth - viewWidth, newX); // Don't allow the FAB past the right hand side of the parent
float newY = motionEvent.getRawY() + dY;
newY = Math.max(0, newY); // Don't allow the FAB past the top of the parent
newY = Math.min(parentHeight - viewHeight, 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();
}
else { // A drag
return true; // Consumed
}
}
else {
return super.onTouchEvent(motionEvent);
}
}
}
这里是XML ...
<com.example.MovableFloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
android:src="@drawable/ic_navigate_next_white_24dp"/>
基本上,您只需在您的XML中将android.support.design.widget.FloatingActionButton
替换为com.example.MovableFloatingActionButton
即可。
答
则只需在任何View
impletementing onTouch
尝试像下面,
XML
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:id="@+id/rootlayout"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
的Java
public class dragativity extends AppCompatActivity implements View.OnTouchListener{
FloatingActionButton fab;
FrameLayout rootlayout;
int _xDelta;
int _yDelta;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.drag);
rootlayout = (FrameLayout) findViewById(R.id.rootlayout);
fab = (FloatingActionButton) findViewById(R.id.fab);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(150, 150);
fab.setLayoutParams(layoutParams);
fab.setOnTouchListener(dragativity.this);
}
public boolean onTouch(View view, MotionEvent event) {
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
FrameLayout.LayoutParams lParams = (FrameLayout.LayoutParams) view.getLayoutParams();
_xDelta = X - lParams.leftMargin;
_yDelta = Y - lParams.topMargin;
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view
.getLayoutParams();
layoutParams.leftMargin = X - _xDelta;
layoutParams.topMargin = Y - _yDelta;
layoutParams.rightMargin = -250;
layoutParams.bottomMargin = -250;
view.setLayoutParams(layoutParams);
break;
}
rootlayout.invalidate();
return true;
}
}
谢谢奥马尔。我一直在尝试这种方法,但没有运气。尽管如此,我还是有一些代码工作的,所以会在一秒之内发布。不管怎么说,还是要谢谢你。 –