Как анимировать щелчок в подвижной плавающей кнопке действия?

Я получаю код для Movable FAB из этого ответа: https://stackoverflow.com/a/46373935

Я считаю, что такая кнопка обычно более удобна для пользователя. Но эта кнопка не меняет свою анимацию при клике — она видит слушателей onClick и уведомляет их при клике, но не меняет свой внешний вид.

Ниже приведен код с двумя плавающими кнопками действий — обычной и подвижной, чтобы вы могли сами увидеть разницу в анимации 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);
        }

    }

}

введите здесь описание изображения введите здесь описание изображения


person Nykyta Avramenko    schedule 31.05.2021    source источник