Circular reveal animation when switching between two views

1k views Asked by At

What I'm trying to achieve

I have a group of buttons in a GridLayout. One of the buttons toggles the function of the other buttons between rounding up and rounding down.

I am trying to implement an animation that changes the color of the buttons in a ripple like effect. The circular reveal animation is the effect I want where the new colour spreads from the touch point on the toggling button to the rest of the other buttons. I only want the animation to grow outward from the touch point in both cases, switching from rounding up to rounding down and back.

Problem

The animation is only working in the first instance from rounding up to rounding down (my app starts with rounding up as the default). There is no animation when switching from rounding down back to rounding up; all the buttons just changes in colour and the toggle button changes icon.

This is my first app so I am having difficulty trying to work out where I've gone wrong.

My methodology and code

In my activity_main.xml layout file, I've created two sets of GridLayouts (each with child buttons) and layered them one on top of the other by wrapping both in a FrameLayout. One set is given a different colour to the other set; I also have a different icon for the toggling button for each set to differentiate between the two rounding method. I've set the visibility attribute on the second GridLayout parent to invisible.

<FrameLayout

    <GridLayout
        android:id="@+id/roundUp"

        <ImageButton
            android:id="@+id/buttonU1"
            ... />
        <Button ... />
        <Button ... />
    </GridLayout>

    <GridLayout
        android:id="@+id/roundDown"
        android:visibility="invisible"

        <ImageButton
            android:id="@+id/buttonD1"
            ... />
        <Button ... />
        <Button ... />
    </GridLayout>

</FrameLayout>

In my MainActivity.java file:

import ...

boolean roundingMode;

public class MainActivity extends AppCompatActivity {

    GridLayout roundUp, roundDown;
    ImageButton buttonU1, buttonD1;
    Button ...

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

        roundUp = (GridLayout) findViewById(R.id.roundUp);
        buttonU1 = (ImageButton) findViewById(R.id.buttonU1);

        roundDown = (GridLayout) findViewById(R.id.roundDown);
        buttonD1 = (ImageButton) findViewById(R.id.buttonD1);

        roundingMode = true;

        buttonU1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                buttonCircularRevealAnim(roundDown);
                roundingMode = false;
            }
        });

        buttonD1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                buttonCircularRevealAnim(roundUp);
                roundingMode = true;
            }
        });
    }

    public void buttonCircularRevealAnim(View view) {

        int originX = roundUp.getWidth() / 2;
        int originY = roundUp.getHeight() / 2;

        float finalRadius = (float) Math.hypot(originX,originY);

        Animator anim;

        if (roundingMode) {

            anim = ViewAnimationUtils.createCircularReveal(roundDown, originX, originY, 0, finalRadius);
            roundDown.setVisibility(View.VISIBLE);
            anim.start();

            anim.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    roundUp.setVisibility(View.INVISIBLE);
                }
            });

        } else {

            anim = ViewAnimationUtils.createCircularReveal(roundUp, originX, originY, 0, finalRadius);
            roundUp.setVisibility(View.VISIBLE);
            anim.start();

            anim.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    roundDown.setVisibility(View.INVISIBLE);
                }
            });
        }
    }

Ignore the fact that I currently have the origin of the animation in the center of the GridLayout. I just want to get the basics working first.

I think the problem lies in the logic and/or the set up of the animation?

I've tried moving the originX, originY and finalRadius calculations into the if statement and using the roundUp (for roundingMode true) and roundDown GridLayouts (for roundingMode false) but that didn't work - so I figure it doesn't matter if it is invisible (in the scenario where you're switching from rounding down to rounding up).

1

There are 1 answers

0
Dennis H On BEST ANSWER

Eventually understood that the circular reveal animation works to reveal an overlapping view that is initially invisible. So in order to use it to change the colour of a view back and forth you have to apply the new colour (from the revealed view) to the view underneath after the animation has ended and then make the revealed view invisible again with the other colour applied to it.

My original code was trying to reveal the view underneath which is of course impossible.

I found the following page very helpful: http://myhexaville.com/2016/12/19/keep-your-app-material/