我从这个答案中得到了 Movable FAB 的代码: https ://stackoverflow.com/a/46373935
我相信这样的按钮通常更方便用户体验。但是这个按钮在点击时不会改变它的动画——它会看到 onClick 监听器并在点击时通知他们,但它不会改变它的外观。
下面的代码带有 2 个浮动操作按钮——普通按钮和可移动按钮,因此您可以自己查看 onClick 动画的区别。
.0. 我的主要问题是——如何使这个可移动按钮的动画与普通按钮的动画完全相同?(动画,除了开始和结束阶段还有过渡阶段。看起来像一个圆圈从您单击按钮的地方开始。为了更好地理解,您可以查看提供的图片或运行代码)。
.1。附加问题——您是否发现使用这个可移动按钮而不是常规按钮有任何缺点(例如程序无法正常运行)?
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floating_action_button"
android:layout_width="90dp"
android:layout_height="90dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="120dp"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="56dp"/>
<com.example.clickablemovable.MovableFloatingActionButton
android:id="@+id/movable_floating_action_button"
android:layout_gravity="bottom|end"
android:clickable="true"
android:layout_width="90dp"
android:layout_height="90dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginEnd="56dp"
android:layout_marginBottom="120dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
public class MainActivity extends AppCompatActivity {
MovableFloatingActionButton mMovableFloatingActionButton;
FloatingActionButton mFloatingActionButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMovableFloatingActionButton = findViewById(R.id.movable_floating_action_button);
mFloatingActionButton = findViewById(R.id.floating_action_button);
mMovableFloatingActionButton.setOnClickListener(view -> showMessage("mMovableFloatingActionButton"));
mFloatingActionButton.setOnClickListener(view -> showMessage("mFloatingActionButton"));
}
private void showMessage(String message) {
Snackbar.make(findViewById(R.id.floating_action_button), message, Snackbar.LENGTH_SHORT).show();
}
}
MovableFloatingActionButton.java
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
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);
}
}
}