Ripple effect animation without touching

I need to do some like ripple effect of Listview item background changing. I try to use ObjectAnimator like this:

AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(activity,
                    R.animator.animator_bkg);
            set.setTarget(childLinear);
            set.setInterpolator(new AccelerateInterpolator());
            set.start(); 

R.animator.animator_bkg:

<objectAnimator
   android:propertyName="backgroundColor"
   android:duration="3000"
   android:valueFrom="@color/white"
   android:valueTo="@color/redTrans"
   android:repeatCount="-1"
   android:repeatMode="reverse"/>

It fluently changes a background (complete filling), but I need gradual filling of ListView item like ripple effect after touch the button.

I think, maybe I can use Canvas with overriding onDraw, but it's to hard for application and it can be some lags.

Upvotes: 4

Views: 1904

Answers (1)

pdegand59
pdegand59

Reputation: 13039

You can do it with a custom view and implement the circular transition in onDraw(), but it's complicated.

You can work around the complexity by using ViewAnimationUtils.createCircularReveal() on sub view. But the draw back is that it's only for API 21+.

In few words, your root layout of the cell has to be a FrameLayout or a RelativeLayout. When the transition starts, you dynamically add 2 views under your cell with the start and the end color, then transition with the circular reveal between the 2. At the end of the transition, you just remove the 2 sub views to keep the view hierarchy a bit cleaner.

Here is the result :

Color reveal

In code :

Cell layout:

<FrameLayout
    android:id="@+id/cell_root"
    android:layout_width="match_parent"
    android:layout_height="72dp">

    <LinearLayout
        android:id="@+id/cell_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="16dp"
        android:background="#FF00FF">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Title"
            android:textSize="18sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="This is content"
            android:textSize="14sp" />
    </LinearLayout>

</FrameLayout>

Code that trigger the background transition :

private void changeBackgroundColor() {
    final FrameLayout startingColorFrame = new FrameLayout(mCellRoot.getContext());
    final FrameLayout endingColorFrame = new FrameLayout(mCellRoot.getContext());
    startingColorFrame.setBackground(mCellContent.getBackground());
    endingColorFrame.setBackground(mPendingColor);
    mCellContent.setBackground(null);
    endingColorFrame.setVisibility(View.GONE);
    mCellRoot.addView(endingColorFrame, 0, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
    mCellRoot.addView(startingColorFrame, 0, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

    int finalRadius = (int) Math.sqrt(mCellRoot.getWidth()*mCellRoot.getWidth() + mCellRoot.getHeight()*mCellRoot.getHeight());
    final int sourceX = mCellRoot.getWidth() / 3;
    final int sourceY = mCellRoot.getHeight() / 2;
    // this is API 21 minimum. Add proper checks
    final Animator circularReveal = ViewAnimationUtils.createCircularReveal(endingColorFrame, sourceX, sourceY, 0, finalRadius);
    endingColorFrame.setVisibility(View.VISIBLE);
    circularReveal.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(final Animator animation) {
            super.onAnimationEnd(animation);
            mStartButton.setEnabled(true);
            mCellContent.setBackground(mPendingColor);
            mPendingColor = startingColorFrame.getBackground();
            mCellRoot.removeView(startingColorFrame);
            mCellRoot.removeView(endingColorFrame);
        }
    });
    // customize the animation here
    circularReveal.setDuration(800);
    circularReveal.setInterpolator(new AccelerateInterpolator());
    circularReveal.start();
}

Upvotes: 2

Related Questions