Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Circular Reveal not working when FAB gravity is bottom

I am working on morphing a floating action button (FAB) to a toolbar and things work smoothly and perfectly with the following code:

layout file:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="sg.com.saurabh.designlibraryexpirements.ToolbarMorphActivity">

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="top|right"
        android:layout_marginTop="@dimen/activity_vertical_margin"
        android:layout_marginRight="@dimen/activity_vertical_margin"
        android:layout_marginBottom="@dimen/activity_vertical_margin"
        android:src="@drawable/ic_add" />

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        style="@style/ToolBarTheme"
        android:layout_height="?attr/actionBarSize"
        android:layout_gravity="top"
        android:layout_marginTop="@dimen/activity_vertical_margin"
        android:layout_marginBottom="@dimen/activity_vertical_margin"
        android:visibility="invisible"
        tools:visibility="visible" />

</FrameLayout>

activity:

package sg.com.saurabh.designlibraryexpirements;

import android.animation.Animator;
import android.os.Bundle;
import android.os.Handler;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.view.animation.FastOutLinearInInterpolator;
import android.support.v4.view.animation.LinearOutSlowInInterpolator;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AnticipateOvershootInterpolator;

public class ToolbarMorphActivity extends AppCompatActivity {

    Toolbar toolbar;
    FloatingActionButton fab;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_toolbar_morph);

        toolbar = (Toolbar) findViewById(R.id.toolbar);
        fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(mFabClickListener);
    }

    private View.OnClickListener mFabClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            fab.animate()
                    .rotationBy(45)
                    .setInterpolator(new AnticipateOvershootInterpolator())
                    .setDuration(250)
                    .start();

            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    fab.setVisibility(View.GONE);
                }
            },50);

            revealToolbar();
        }
    };

    private void revealToolbar() {
        toolbar.setVisibility(View.VISIBLE);

        int x = (int)fab.getX() + fab.getWidth()/2;
        int y = (int)fab.getY() + fab.getHeight()/2;

        Animator animator = ViewAnimationUtils.createCircularReveal(toolbar, x, y, 0, toolbar.getWidth())
                .setDuration(400);
        animator.setInterpolator(new FastOutLinearInInterpolator());
        animator.start();
    }

    private void dismissToolbar() {
        int x = (int)fab.getX() + fab.getWidth()/2;
        int y = (int)fab.getY() + fab.getHeight()/2;

        Animator animator = ViewAnimationUtils.createCircularReveal(toolbar, x, y, toolbar.getWidth(), 0)
                .setDuration(400);
        animator.setInterpolator(new LinearOutSlowInInterpolator());
        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                toolbar.setVisibility(View.INVISIBLE);
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        animator.start();

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                fab.setVisibility(View.VISIBLE);

                fab.animate()
                        .rotationBy(-45)
                        .setInterpolator(new AccelerateInterpolator())
                        .setDuration(100)
                        .start();
            }
        },200);
    }

    @Override
    public void onBackPressed() {
        if(toolbar.getVisibility() == View.VISIBLE) {
            dismissToolbar();
        }
        else
            super.onBackPressed();
    }
}

The circular reveal works as expected for the above layout. However thing break up when I change the layout_gravity of the fab and toolbar to bottom instead of top. The rotate animation works and then the toolbar just appears without the circular reveal animation. I am completely stumped by how that breaks the circular reveal animation.

like image 302
Saurabh Avatar asked Jan 19 '16 17:01

Saurabh


1 Answers

enter image description here

The fix for you would be to replace:

private void revealToolbar() {
    ....
    int x = (int)fab.getX() + fab.getWidth()/2;
    int y = (int)fab.getY() + fab.getHeight()/2;
    ....
}

by

 private void revealToolbar() {
    ...
    int x = (int)fab.getX() + fab.getWidth()/2;
    int y = fab.getHeight()/2;
    ...
 }

The reason is that createCircularReveal is taking parameters centerY and centerX as coordinates of the center of the animating circle, relative to view (i.e. Toolbar, in our case).

See method ViewAnimationUtils.createCircularReveal definition:

 ........
 * @param view The View will be clipped to the animating circle.
 * @param centerX The x coordinate of the center of the animating circle, relative to
 *                <code>view</code>.
 * @param centerY The y coordinate of the center of the animating circle, relative to
 *                <code>view</code>.
 * @param startRadius The starting radius of the animating circle.
 * @param endRadius The ending radius of the animating circle.
 */
like image 78
Konstantin Loginov Avatar answered Nov 10 '22 23:11

Konstantin Loginov