package at.markushi.ui;
import com.linju.android_property2.R;
import android.animation.Animator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import at.markushi.ui.util.BakedBezierInterpolator;
import at.markushi.ui.util.UiHelper;
@SuppressLint("NewApi")
public class RevealColorView extends ViewGroup {
public static final int ANIMATION_REVEAL = 0;
public static final int ANIMATION_HIDE = 2;
private static final float SCALE = 8f;
private View inkView;
private int inkColor;
private ShapeDrawable circle;
private ViewPropertyAnimator animator;
public RevealColorView(Context context) {
this(context, null);
}
public RevealColorView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RevealColorView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (isInEditMode()) {
return;
}
inkView = new View(context);
addView(inkView);
circle = new ShapeDrawable(new OvalShape());
UiHelper.setBackground(inkView, circle);
inkView.setVisibility(View.INVISIBLE);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
inkView.layout(left, top, left + inkView.getMeasuredWidth(), top + inkView.getMeasuredHeight());
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = MeasureSpec.getSize(widthMeasureSpec);
final int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
final float circleSize = (float) Math.sqrt(width * width + height * height) * 2f;
final int size = (int) (circleSize / SCALE);
final int sizeSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
inkView.measure(sizeSpec, sizeSpec);
}
public void reveal(final int x, final int y, final int color, Animator.AnimatorListener listener) {
final int duration = getResources().getInteger(R.integer.rcv_animationDurationReveal);
reveal(x, y, color, 0, duration, listener);
}
public void reveal(final int x, final int y, final int color, final int startRadius, long duration, final Animator.AnimatorListener listener) {
if (color == inkColor) {
return;
}
inkColor = color;
if (animator != null) {
animator.cancel();
}
circle.getPaint().setColor(color);
inkView.setVisibility(View.VISIBLE);
final float startScale = startRadius * 2f / inkView.getHeight();
final float finalScale = calculateScale(x, y) * SCALE;
prepareView(inkView, x, y, startScale);
animator = inkView.animate().scaleX(finalScale).scaleY(finalScale).setDuration(duration).setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
if (listener != null) {
listener.onAnimationStart(animator);
}
}
@Override
public void onAnimationEnd(Animator animation) {
setBackgroundColor(color);
inkView.setVisibility(View.INVISIBLE);
if (listener != null) {
listener.onAnimationEnd(animation);
}
}
@Override
public void onAnimationCancel(Animator animator) {
if (listener != null) {
listener.onAnimationCancel(animator);
}
}
@Override
public void onAnimationRepeat(Animator animator) {
if (listener != null) {
listener.onAnimationRepeat(animator);
}
}
});
prepareAnimator(animator, ANIMATION_REVEAL);
animator.start();
}
public void hide(final int x, final int y, final int color, final Animator.AnimatorListener listener) {
final int duration = getResources().getInteger(R.integer.rcv_animationDurationHide);
hide(x, y, color, 0, duration, listener);
}
public void hide(final int x, final int y, final int color, final int endRadius, final long duration, final Animator.AnimatorListener listener) {
inkColor = Color.TRANSPARENT;
if (animator != null) {
animator.cancel();
}
inkView.setVisibility(View.VISIBLE);
setBackgroundColor(color);
final float startScale = calculateScale(x, y) * SCALE;
final float finalScale = endRadius * SCALE / inkView.getWidth();
prepareView(inkView, x, y, startScale);
animator = inkView.animate().scaleX(finalScale).scaleY(finalScale).setDuration(duration).setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
if (listener != null) {
listener.onAnimationStart(animator);
}
}
@Override
public void onAnimationEnd(Animator animation) {
inkView.setVisibility(View.INVISIBLE);
if (listener != null) {
listener.onAnimationEnd(animation);
}
}
@Override
public void onAnimationCancel(Animator animator) {
if (listener != null) {
listener.onAnimationCancel(animator);
}
}
@Override
public void onAnimationRepeat(Animator animator) {
if (listener != null) {
listener.onAnimationRepeat(animator);
}
}
});
prepareAnimator(animator, ANIMATION_HIDE);
animator.start();
}
public ViewPropertyAnimator prepareAnimator(ViewPropertyAnimator animator, int type) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
animator.withLayer();
}
animator.setInterpolator(BakedBezierInterpolator.getInstance());
return animator;
}
private void prepareView(View view, int x, int y, float scale) {
final int centerX = (view.getWidth() / 2);
final int centerY = (view.getHeight() / 2);
view.setTranslationX(x - centerX);
view.setTranslationY(y - centerY);
view.setPivotX(centerX);
view.setPivotY(centerY);
view.setScaleX(scale);
view.setScaleY(scale);
}
/**
* calculates the required scale of the ink-view to fill the whole view
*
* @param x circle center x
* @param y circle center y
* @return
*/
private float calculateScale(int x, int y) {
final float centerX = getWidth() / 2f;
final float centerY = getHeight() / 2f;
final float maxDistance = (float) Math.sqrt(centerX * centerX + centerY * centerY);
final float deltaX = centerX - x;
final float deltaY = centerY - y;
final float distance = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY);
final float scale = 0.5f + (distance / maxDistance) * 0.5f;
return scale;
}
}