ozodrukh / CircularReveal

Lollipop ViewAnimationUtils.createCircularReveal for everyone 4.0+
MIT License
2.43k stars 391 forks source link

RevealFrameLayout first opening bug #70

Closed ccentauri closed 8 years ago

ccentauri commented 8 years ago

Hi! I use this awesome library to create CircularReveal animation in RecyclerView when SearchView is pressed and I have a little bug. Animation works fine, but only after first open and close of SearchView. When I open Activity and press SearchView, RecyclerView appears without CircularReveal animation, and when I close it and open again, all works fine.

Here is my XML:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/tools"
    xmlns:fab="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/root_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    tools:context=".MapsActivity">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/toolbar">

        <fragment xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:tools="http://schemas.android.com/tools"
            android:id="@+id/map"
            android:name="com.google.android.gms.maps.SupportMapFragment"
            class="com.google.android.gms.maps.MapFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context="ua.nau.edu.NAU_Guide.MapsActivity"
            tools:layout="@layout/fragment_maps" />

    </RelativeLayout>

    <include
        android:id="@+id/toolbar"
        layout="@layout/toolbar" />

    <io.codetail.widget.RevealFrameLayout
        android:id="@+id/reveal_recycler"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/toolbar">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerview_user_data"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/grey_bg"
            android:visibility="gone" />
    </io.codetail.widget.RevealFrameLayout>
</RelativeLayout>

My Animation methods:

private void revealShow(final View view) {
            // get the center for the clipping circle
            int cx = (view.getLeft() + view.getRight()) / 2;
            int cy = (view.getTop() + view.getBottom()) / 2;

            // get the final radius for the clipping circle
            int dx = Math.max(cx, view.getWidth() - cx);
            int dy = Math.max(cy, view.getHeight() - cy);
            float finalRadius = (float) Math.hypot(dx, dy);

            SupportAnimator animator = ViewAnimationUtils.createCircularReveal(view, cx, cy, 0, finalRadius);
            animator.setInterpolator(new AccelerateDecelerateInterpolator());
            animator.setDuration(300);
            view.setVisibility(View.VISIBLE);
            animator.start();

        }

        private void revealClose(final View view) {
            // get the center for the clipping circle
            int cx = (view.getLeft() + view.getRight()) / 2;
            int cy = (view.getTop() + view.getBottom()) / 2;

            // get the final radius for the clipping circle
            int dx = Math.max(cx, view.getWidth() - cx);
            int dy = Math.max(cy, view.getHeight() - cy);
            float finalRadius = (float) Math.hypot(dx, dy);

            SupportAnimator animator = ViewAnimationUtils.createCircularReveal(view, cx, cy, 0, finalRadius);
            animator.setInterpolator(new AccelerateDecelerateInterpolator());
            animator.setDuration(300);
            animator = animator.reverse();
            animator.start();

            view.postDelayed(new Runnable() {
                @Override
                public void run() {
                    view.setVisibility(View.GONE);
                }
            }, 300);

        }

My SearchView's OnClickListener:

searchView.setOnSearchClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //Show RecyclerView
                revealShow(recyclerView);

                ...
            }
        });

My SearchView's OnCloseListener:

searchView.setOnCloseListener(new SearchView.OnCloseListener() {
            @Override
            public boolean onClose() {
                Log.d(TAG, "OnCloseListener/ onClose() called");

                // Hide keyboard
                if (getCurrentFocus() != null) {
                    methodManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
                }

                // Close RecyclerView & SearchView
                searchView.onActionViewCollapsed();
                revealClose(recyclerView);

                return true;
            }
        });
srecatala commented 8 years ago

The problem here is that you're initially setting your View's visibility to 'gone'. If the visibility is 'gone', your view is not taken into account for layout purposes, so all its layout parameters, such as width, height, top or bottom have a value of 0.

The first time you call the revealShow method you are creating a circular reveal animation of radius=0, hence you don't see anything. After this call, the right layout parameters for the View will be calculated, since you changed the visibility to 'visible'. That way, all subsequent circular reveal animations will have the correct radius.

Solution: change the View's visibility to 'invisible'. That way, opposite to 'gone', the view will be taken into account when layout takes place.