Android Open Source - Genius-Android Touch Effect Animator






From Project

Back to project page Genius-Android.

License

The source code is released under:

Apache License

If you think the Android project Genius-Android listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (C) 2014 Qiujuer <qiujuer@live.cn>
 * WebSite http://www.qiujuer.net//w w  w  .jav a  2  s  . c  om
 * Created 01/06/2015
 * Changed 01/13/2015
 * Version 2.0.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.qiujuer.genius.animation;

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.Transformation;

import static android.graphics.Paint.ANTI_ALIAS_FLAG;

/**
 * Created by Qiujuer
 * on 2015/01/06.
 * <p/>
 * This class adds touch effects to the given View. The effect animation is triggered by onTouchEvent
 * of the View and this class is injected into the onDraw function of the View to perform animation.
 * You should in your View onMeasure() call to this class.
 */
public class TouchEffectAnimator {
    private static final Interpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator(2.8f);
    private static final Interpolator ACCELERATE_INTERPOLATOR = new AccelerateInterpolator();
    private static final int EASE_ANIM_DURATION = 180;
    private static final int RIPPLE_ANIM_DURATION = 250;
    // 255*0.70
    private static final int MAX_BACK_ALPHA = 180;
    private static final int MAX_RIPPLE_ALPHA = 255;

    private View mView;
    private int mClipRadius;
    private int mAnimDuration = RIPPLE_ANIM_DURATION;
    private TouchEffect mTouchEffect = TouchEffect.Move;
    private Animation mFadeInAnimation = null;
    private Animation mFadeOutAnimation = null;

    private float mStartRadius;
    private float mEndRadius;
    private float mRadius;

    private float mDownX, mDownY;
    private float mCenterX, mCenterY;
    private float mPaintX, mPaintY;

    private Paint mPaint = new Paint(ANTI_ALIAS_FLAG);
    private RectF mRectRectR = new RectF();
    private Path mRectPath = new Path();
    private int mEndBackAlpha = MAX_BACK_ALPHA;
    private int mEndRippleAlpha = MAX_RIPPLE_ALPHA;
    private int mBackAlpha = 0;
    private int mRippleAlpha = 0;

    private boolean isTouchReleased = false;
    private boolean isAnimatingFadeIn = false;
    private boolean isInterceptClick = false;
    private boolean isAnimation = false;

    // To call view performClick
    private PerformClick mPerformClick;


    public TouchEffectAnimator(View mView) {
        this.mView = mView;
        mPaint = new Paint(ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        onMeasure();
    }

    public void setAnimDuration(int animDuration) {
        this.mAnimDuration = animDuration;
    }

    public TouchEffect getTouchEffect() {
        return mTouchEffect;
    }

    public void setTouchEffect(TouchEffect touchEffect) {
        mTouchEffect = touchEffect;
        if (mTouchEffect == TouchEffect.Ease)
            mAnimDuration = EASE_ANIM_DURATION;

        onMeasure();
    }

    public void setEffectColor(int effectColor) {
        mPaint.setColor(effectColor);

        int alpha = (effectColor >> 24) & 0xff;
        if (alpha != 255) {
            mEndBackAlpha = (int) (MAX_BACK_ALPHA * (alpha / 255.0f));
            mEndRippleAlpha = (int) (MAX_RIPPLE_ALPHA * (alpha / 255.0f));
        }
    }

    public void setClipRadius(int mClipRadius) {
        this.mClipRadius = mClipRadius;
    }

    public boolean interceptClick() {
        isInterceptClick = true;
        return isAnimation;
    }

    public void onMeasure() {
        mCenterX = mView.getWidth() / 2;
        mCenterY = mView.getHeight() / 2;

        mRectRectR.set(0, 0, mView.getWidth(), mView.getHeight());

        mRectPath.reset();
        mRectPath.addRoundRect(mRectRectR, mClipRadius, mClipRadius, Path.Direction.CW);
    }

    public void onTouchEvent(final MotionEvent event) {
        // On disEnable return
        if (!mView.isEnabled())
            return;

        if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) {
            isTouchReleased = true;
            if (!isAnimatingFadeIn) {
                fadeOutEffect();
            }
        }
        if (event.getActionMasked() == MotionEvent.ACTION_UP) {
            isTouchReleased = true;
            if (!isAnimatingFadeIn) {
                fadeOutEffect();
            }
        } else if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
            // Set default operation to fadeOutEffect()
            isTouchReleased = false;

            // Set this start point
            mPaintX = mDownX = event.getX();
            mPaintY = mDownY = event.getY();

            // This color alpha
            mBackAlpha = 0;
            mRippleAlpha = 255;

            // Gets the bigger value (width or height) to fit the circle
            mEndRadius = mCenterX > mCenterY ? mCenterX : mCenterY;
            mStartRadius = 0;
            mRadius = 0;

            // This circle radius is 78% 90% or fill all
            switch (mTouchEffect) {
                case Ripple:
                    float x = mDownX < mCenterX ? 2 * mCenterX : 0;
                    float y = mDownY < mCenterY ? 2 * mCenterY : 0;
                    mEndRadius = (float) Math.sqrt((x - mDownX) * (x - mDownX) + (y - mDownY) * (y - mDownY));
                    break;
                case Move:
                    mStartRadius = 0;
                    mEndRadius *= 0.78;
                    break;
                case Press:
                    mStartRadius = mEndRadius * 0.6f;
                    mEndRadius *= 0.9;
                    mPaintX = mCenterX;
                    mPaintY = mCenterY;
                    break;
            }

            // Cancel and Start new animation
            cancelEffect();
            fadeInEffect();
        }
    }

    public void onDraw(final Canvas canvas) {
        // Draw Background
        if (mTouchEffect != TouchEffect.Press && mBackAlpha != 0) {
            mPaint.setAlpha(mBackAlpha);
            canvas.drawPath(mRectPath, mPaint);
        }

        // Draw Ripple
        if (mRadius != 0) {
            // Canvas Clip
            canvas.save();
            canvas.clipPath(mRectPath);
            mPaint.setAlpha(mRippleAlpha);
            canvas.drawCircle(mPaintX, mPaintY, mRadius, mPaint);
            canvas.restore();
        }
    }

    private void fadeInEffect() {
        mFadeInAnimation = new Animation() {
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) {
                switch (mTouchEffect) {
                    case Ease:
                        mBackAlpha = (int) (interpolatedTime * mEndBackAlpha);
                        break;
                    case Ripple:
                        mBackAlpha = (int) (interpolatedTime * mEndBackAlpha);
                        mRadius = mStartRadius + (mEndRadius - mStartRadius) * interpolatedTime;
                        break;
                    case Move:
                        mBackAlpha = (int) (interpolatedTime * mEndBackAlpha);
                        mRadius = mEndRadius * interpolatedTime;
                        mPaintX = mDownX + (mCenterX - mDownX) * interpolatedTime;
                        mPaintY = mDownY + (mCenterY - mDownY) * interpolatedTime;
                        break;
                    case Press:
                        mRadius = mStartRadius + (mEndRadius - mStartRadius) * interpolatedTime;
                        mRippleAlpha = (int) (interpolatedTime * mEndRippleAlpha);
                        break;
                }
                mView.invalidate();
            }
        };
        mFadeInAnimation.setInterpolator(DECELERATE_INTERPOLATOR);
        mFadeInAnimation.setDuration(mAnimDuration);
        mFadeInAnimation.setAnimationListener(mFadeInAnimationListener);
        mView.startAnimation(mFadeInAnimation);
    }

    private void fadeOutEffect() {
        mFadeOutAnimation = new Animation() {
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) {
                mBackAlpha = (int) (mEndBackAlpha - (mEndBackAlpha * interpolatedTime));
                if (mTouchEffect == TouchEffect.Press) {
                    mRippleAlpha = (int) (mEndRippleAlpha - (mEndRippleAlpha * interpolatedTime));
                    mRadius = mEndRadius + (mStartRadius - mEndRadius) * interpolatedTime;
                } else {
                    mRadius = 0;
                }
                mView.invalidate();
            }
        };
        mFadeOutAnimation.setInterpolator(ACCELERATE_INTERPOLATOR);
        mFadeOutAnimation.setDuration(EASE_ANIM_DURATION);
        mFadeOutAnimation.setAnimationListener(mFadeOutAnimationListener);
        mView.startAnimation(mFadeOutAnimation);
    }

    private void cancelEffect() {
        if (mFadeInAnimation != null) {
            mFadeInAnimation.setAnimationListener(null);
            mFadeInAnimation.cancel();
        }

        if (mFadeOutAnimation != null) {
            mFadeOutAnimation.setAnimationListener(null);
            mFadeOutAnimation.cancel();
        }

        isAnimation = false;
    }

    private void performClick() {
        if (mPerformClick == null)
            mPerformClick = new PerformClick();
        if (!mView.post(mPerformClick)) {
            mView.performClick();
        }
    }

    private Animation.AnimationListener mFadeInAnimationListener = new Animation.AnimationListener() {

        @Override
        public void onAnimationStart(Animation animation) {
            isAnimatingFadeIn = true;
            isAnimation = true;
        }

        @Override
        public void onAnimationEnd(Animation animation) {
            isAnimatingFadeIn = false;
            // Is un touch auto fadeOutEffect()
            if (isTouchReleased) fadeOutEffect();
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
        }
    };

    private Animation.AnimationListener mFadeOutAnimationListener = new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {

        }

        @Override
        public void onAnimationEnd(Animation animation) {
            isAnimation = false;

            if (isInterceptClick) {
                isInterceptClick = false;
                performClick();
            }
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
        }
    };

    private final class PerformClick implements Runnable {
        @Override
        public void run() {
            mView.performClick();
        }
    }
}




Java Source Code List

net.qiujuer.genius.ApplicationTest.java
net.qiujuer.genius.Attributes.java
net.qiujuer.genius.GeniusUI.java
net.qiujuer.genius.Genius.java
net.qiujuer.genius.animation.TouchEffectAnimator.java
net.qiujuer.genius.animation.TouchEffect.java
net.qiujuer.genius.app.BlurKit.java
net.qiujuer.genius.app.BlurNative.java
net.qiujuer.genius.app.UIKitHandlerPoster.java
net.qiujuer.genius.app.UIKitSyncPost.java
net.qiujuer.genius.app.UIKit.java
net.qiujuer.genius.command.CommandExecutor.java
net.qiujuer.genius.command.CommandService.java
net.qiujuer.genius.command.Command.java
net.qiujuer.genius.nettool.DnsResolve.java
net.qiujuer.genius.nettool.NetModel.java
net.qiujuer.genius.nettool.Ping.java
net.qiujuer.genius.nettool.Telnet.java
net.qiujuer.genius.nettool.TraceRouteContainer.java
net.qiujuer.genius.nettool.TraceRouteThread.java
net.qiujuer.genius.nettool.TraceRoute.java
net.qiujuer.genius.sample.ApplicationTest.java
net.qiujuer.genius.sample.CaseActivity.java
net.qiujuer.genius.sample.MainActivity.java
net.qiujuer.genius.sample.TwoActivity.java
net.qiujuer.genius.util.FixedList.java
net.qiujuer.genius.util.GeniusException.java
net.qiujuer.genius.util.HashUtils.java
net.qiujuer.genius.util.LogWriter.java
net.qiujuer.genius.util.Log.java
net.qiujuer.genius.util.Tools.java
net.qiujuer.genius.widget.GeniusButton.java
net.qiujuer.genius.widget.GeniusCheckBox.java
net.qiujuer.genius.widget.GeniusTextView.java