可移动的浮动动作按钮移出屏幕
Movable floating action button moves out of the screen
在我的项目中,我实现了可移动的浮动按钮,但是当它移到角落外时,它会移出屏幕。我希望它尊重屏幕边界。请帮助我实施。
fab.setOnTouchListener(new View.OnTouchListener() {
float startX;
float startRawX;
float distanceX;
int lastAction;
@Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
startX = view.getX() - event.getRawX();
startRawX = event.getRawX();
lastAction = MotionEvent.ACTION_DOWN;
break;
case MotionEvent.ACTION_MOVE:
view.setX(event.getRawX() + startX);
view.setY(event.getRawY() + startX);
lastAction = MotionEvent.ACTION_MOVE;
break;
case MotionEvent.ACTION_UP:
distanceX = event.getRawX()-startRawX;
if (Math.abs(distanceX)< 10){
ScanQRcode(); }
break;
case MotionEvent.ACTION_BUTTON_PRESS:
default:
return false;
}
return true;
}
});
请检查下方 class 及其 XML
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;
import android.view.ViewGroup;
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){
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();
}
else { // A drag
return true; // Consumed
}
}
else {
return super.onTouchEvent(motionEvent);
}
}
}
这里是 XML 的 MovableFloatingActionButton
<com.example.MovableFloatingActionButton
android:id="@+id/btnFab"
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"/>
要实现您的目标,需要遵循几个步骤:
首先你需要知道浮动按钮可以自由移动的工作区域的高度和宽度。
为此,您可以这样做:
int 屏幕高度,屏幕宽度;
root.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
root.getViewTreeObserver().removeOnGlobalLayoutListener(this);
screenHeight = root.getHeight();
screenWidth = root.getWidth();
}
});
这里的root是浮动按钮可以自由移动的父视图。
您可以将此代码放在 activity
的 onCreate 中
接下来你要计算浮动按钮的半径。这可以像这样完成:
int 中心;
Rect rectf = new Rect();
fab.getGlobalVisibleRect(rectf);
int height = rectf.height();
int width = rectf.width();
center = width/2;
瞧,现在您拥有了所需的号码。您现在需要做的就是在 fab 按钮上设置一个 onTouchListener 并在 MotionEvent.ACTION_MOVE 检查您的 fab 按钮的中心坐标 + 它的半径是否等于或超过屏幕宽度或负数(如果水平移动)或中心坐标+ 它的半径超过屏幕高度或负值(如果垂直移动)。在这两种情况中的任何一种情况下,只需将晶圆厂移回适用的左侧、右侧、顶部或底部边缘。例如:如果 fab 向上移动并达到 0 x 坐标(我将整个屏幕视为可移动区域),那么我们可以将 fab 的 x 坐标设置为 fab 视图的宽度除以 2,这样 id 就不会' 移动到可移动屏幕区域上方。
可以应用类似的逻辑来防止 fab 按钮向左、向右或父级底部移动。祝你好运!
在我的项目中,我实现了可移动的浮动按钮,但是当它移到角落外时,它会移出屏幕。我希望它尊重屏幕边界。请帮助我实施。
fab.setOnTouchListener(new View.OnTouchListener() {
float startX;
float startRawX;
float distanceX;
int lastAction;
@Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
startX = view.getX() - event.getRawX();
startRawX = event.getRawX();
lastAction = MotionEvent.ACTION_DOWN;
break;
case MotionEvent.ACTION_MOVE:
view.setX(event.getRawX() + startX);
view.setY(event.getRawY() + startX);
lastAction = MotionEvent.ACTION_MOVE;
break;
case MotionEvent.ACTION_UP:
distanceX = event.getRawX()-startRawX;
if (Math.abs(distanceX)< 10){
ScanQRcode(); }
break;
case MotionEvent.ACTION_BUTTON_PRESS:
default:
return false;
}
return true;
}
});
请检查下方 class 及其 XML
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;
import android.view.ViewGroup;
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){
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();
}
else { // A drag
return true; // Consumed
}
}
else {
return super.onTouchEvent(motionEvent);
}
}
}
这里是 XML 的 MovableFloatingActionButton
<com.example.MovableFloatingActionButton
android:id="@+id/btnFab"
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"/>
要实现您的目标,需要遵循几个步骤:
首先你需要知道浮动按钮可以自由移动的工作区域的高度和宽度。 为此,您可以这样做:
int 屏幕高度,屏幕宽度;
root.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
root.getViewTreeObserver().removeOnGlobalLayoutListener(this);
screenHeight = root.getHeight();
screenWidth = root.getWidth();
}
});
这里的root是浮动按钮可以自由移动的父视图。 您可以将此代码放在 activity
的 onCreate 中接下来你要计算浮动按钮的半径。这可以像这样完成:
int 中心;
Rect rectf = new Rect();
fab.getGlobalVisibleRect(rectf);
int height = rectf.height();
int width = rectf.width();
center = width/2;
瞧,现在您拥有了所需的号码。您现在需要做的就是在 fab 按钮上设置一个 onTouchListener 并在 MotionEvent.ACTION_MOVE 检查您的 fab 按钮的中心坐标 + 它的半径是否等于或超过屏幕宽度或负数(如果水平移动)或中心坐标+ 它的半径超过屏幕高度或负值(如果垂直移动)。在这两种情况中的任何一种情况下,只需将晶圆厂移回适用的左侧、右侧、顶部或底部边缘。例如:如果 fab 向上移动并达到 0 x 坐标(我将整个屏幕视为可移动区域),那么我们可以将 fab 的 x 坐标设置为 fab 视图的宽度除以 2,这样 id 就不会' 移动到可移动屏幕区域上方。
可以应用类似的逻辑来防止 fab 按钮向左、向右或父级底部移动。祝你好运!