Анимация Fab на клик (увеличение/уменьшение)

Я пытаюсь подражать анимации и изменению цвета для следующей кнопки с плавающим действием.

Как работает кнопка с плавающим действием, белый выключен и синий горит.

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

Однако, я не увенчался успехом анимации и изменил цвет.

Это были мои попытки сделать это, так как вы можете видеть, что я прокомментировал все разные способы, которыми я пытался это сделать.

Это мой код:

    @SuppressWarnings("unused")
    @OnClick(R.id.fabMovieFavourite)
    public void addMovieFavourite(View view) {
 /*       final Animator animator = AnimatorInflater.loadAnimator(getActivity(), R.animator.add_favourite_movie);
        animator.setTarget(view);)
        animator.start();
 */
/*
        AnimatorSet animatorSet = new AnimatorSet();
        PropertyValuesHolder propertyValuesHolderX = PropertyValuesHolder.ofFloat(View.SCALE_X, 1.1f);
        PropertyValuesHolder propertyValuesHolderY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1.1f);
        ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(view, propertyValuesHolderX, propertyValuesHolderY);
        objectAnimator.setDuration(300);
        objectAnimator.setInterpolator(new OvershootInterpolator(10f));
*/

        /*
        objectAnimator.setRepeatCount(1);
        objectAnimator.setRepeatMode(ObjectAnimator.REVERSE);
*/

/*
        PropertyValuesHolder propertyValuesHolderX2 = PropertyValuesHolder.ofFloat(View.SCALE_X, 0.9f);
        PropertyValuesHolder propertyValuesHolderY2 = PropertyValuesHolder.ofFloat(View.SCALE_Y, 0.9f);
        ObjectAnimator objectAnimator2 = ObjectAnimator.ofPropertyValuesHolder(view, propertyValuesHolderX2, propertyValuesHolderY2);
        objectAnimator.setDuration(300);
        objectAnimator2.setInterpolator(new OvershootInterpolator(10f));

        animatorSet.playSequentially(objectAnimator, objectAnimator2);
        objectAnimator.start();
*/

      //  view.BackgroundTintList(ContextCompat.getColorStateList(getContext(), R.color.primary));
        //view.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.primary));

        if(Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
            Timber.d("start translationZ");
            ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, View.TRANSLATION_Z, 12f);
            objectAnimator.setDuration(300);
            objectAnimator.setInterpolator(new OvershootInterpolator(10f));
            objectAnimator.setTarget(view);
            objectAnimator.start();
        }
    }

Большое спасибо за любые предложения.

Ответы

Ответ 1

В этой анимации есть две фазы. Сначала он масштабирует оси X и Y, а второй уменьшает масштаб. Итак, мы можем разделить их на два AnimatorSet и последовательно воспроизводить их.

Ключевой момент анимации - найти соответствующий интерполятор для второго AnimatorSet, потому что он не является стандартным.

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

Посмотрите, мы хотим, чтобы fab перевыполнил, затем недосчитался, а затем, наконец, доработал до указанного значения в аниматоре.

К счастью, очень удобно PathInterpolator, что создаст для нас интерполятор с предоставленным Path.

Path path = new Path();
path.moveTo(0.0f, 0.0f);
path.lineTo(0.5f, 1.3f);
path.lineTo(0.75f, 0.8f);
path.lineTo(1.0f, 1.0f);
PathInterpolator pathInterpolator = new PathInterpolator(path);

Итак, создадим первую анимацию:

final float from = 1.0f;
final float to = 1.3f;

ObjectAnimator scaleX = ObjectAnimator.ofFloat(fab, View.SCALE_X, from, to);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(fab, View.SCALE_Y,  from, to);
ObjectAnimator translationZ = ObjectAnimator.ofFloat(fab, View.TRANSLATION_Z, from, to);

AnimatorSet set1 = new AnimatorSet();
set1.playTogether(scaleX, scaleY, translationZ);
set1.setDuration(100);
set1.setInterpolator(new AccelerateInterpolator());

set1.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
        fab.setImageResource(isActive ? R.drawable.heart_active : R.drawable.heart_passive);
        fab.setBackgroundTintList(ColorStateList.valueOf(isActive ? colorActive : colorPassive));
        isActive = !isActive;
    }
});

Мы масштабируем как x, y. Кроме того, мы меняем z-перевод на соответствующий эффект теней. Когда анимация заканчивается, мы хотим изменить состояние fab (цвет сердца и фона).

Теперь давайте создадим анимацию для установки:

ObjectAnimator scaleXBack = ObjectAnimator.ofFloat(fab, View.SCALE_X, to, from);
ObjectAnimator scaleYBack = ObjectAnimator.ofFloat(fab, View.SCALE_Y, to, from);
ObjectAnimator translationZBack = ObjectAnimator.ofFloat(fab, View.TRANSLATION_Z, to, from);

AnimatorSet set2 = new AnimatorSet();
set2.playTogether(scaleXBack, scaleYBack, translationZBack);
set2.setDuration(300);
set2.setInterpolator(pathInterpolator);

См. здесь, мы использовали PathInterpolator, который мы создали ранее.

Мы хотим последовательно воспроизводить эти два AnimatorSet:

final AnimatorSet set = new AnimatorSet();
set.playSequentially(set1, set2);

set.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
        fab.setClickable(true);
    }

    @Override
    public void onAnimationStart(Animator animation) {
        fab.setClickable(false);
    }
});

Кроме того, мы хотим отключить клики на Fab во время анимации. Поэтому мы включаем/выключаем его в зависимости от состояния анимации.

Наконец, мы запускаем анимацию, когда происходит клик:

fab.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        set.start();
    }
});

Результат:

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

Исходный код в github