KeyguardAffordanceViewpublic class KeyguardAffordanceView extends android.widget.ImageView An ImageView which does not have overlapping renderings commands and therefore does not need a
layer when alpha is changed. |
Fields Summary |
---|
private static final long | CIRCLE_APPEAR_DURATION | private static final long | CIRCLE_DISAPPEAR_MAX_DURATION | private static final long | NORMAL_ANIMATION_DURATION | public static final float | MAX_ICON_SCALE_AMOUNT | public static final float | MIN_ICON_SCALE_AMOUNT | private final int | mMinBackgroundRadius | private final android.graphics.Paint | mCirclePaint | private final android.view.animation.Interpolator | mAppearInterpolator | private final android.view.animation.Interpolator | mDisappearInterpolator | private final int | mInverseColor | private final int | mNormalColor | private final android.animation.ArgbEvaluator | mColorInterpolator | private final FlingAnimationUtils | mFlingAnimationUtils | private final android.graphics.drawable.Drawable | mArrowDrawable | private final int | mHintChevronPadding | private float | mCircleRadius | private int | mCenterX | private int | mCenterY | private android.animation.ValueAnimator | mCircleAnimator | private android.animation.ValueAnimator | mAlphaAnimator | private android.animation.ValueAnimator | mScaleAnimator | private android.animation.ValueAnimator | mArrowAnimator | private float | mCircleStartValue | private boolean | mCircleWillBeHidden | private int[] | mTempPoint | private float | mImageScale | private int | mCircleColor | private boolean | mIsLeft | private float | mArrowAlpha | private android.view.View | mPreviewView | private float | mCircleStartRadius | private float | mMaxCircleSize | private android.animation.Animator | mPreviewClipper | private android.animation.AnimatorListenerAdapter | mClipEndListener | private android.animation.AnimatorListenerAdapter | mCircleEndListener | private android.animation.AnimatorListenerAdapter | mScaleEndListener | private android.animation.AnimatorListenerAdapter | mAlphaEndListener | private android.animation.AnimatorListenerAdapter | mArrowEndListener |
Constructors Summary |
---|
public KeyguardAffordanceView(android.content.Context context)
this(context, null);
| public KeyguardAffordanceView(android.content.Context context, android.util.AttributeSet attrs)
this(context, attrs, 0);
| public KeyguardAffordanceView(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr)
this(context, attrs, defStyleAttr, 0);
| public KeyguardAffordanceView(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr, int defStyleRes)
super(context, attrs, defStyleAttr, defStyleRes);
mCirclePaint = new Paint();
mCirclePaint.setAntiAlias(true);
mCircleColor = 0xffffffff;
mCirclePaint.setColor(mCircleColor);
mNormalColor = 0xffffffff;
mInverseColor = 0xff000000;
mMinBackgroundRadius = mContext.getResources().getDimensionPixelSize(
R.dimen.keyguard_affordance_min_background_radius);
mHintChevronPadding = mContext.getResources().getDimensionPixelSize(
R.dimen.hint_chevron_circle_padding);
mAppearInterpolator = AnimationUtils.loadInterpolator(mContext,
android.R.interpolator.linear_out_slow_in);
mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext,
android.R.interpolator.fast_out_linear_in);
mColorInterpolator = new ArgbEvaluator();
mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.3f);
mArrowDrawable = context.getDrawable(R.drawable.ic_chevron_left);
mArrowDrawable.setBounds(0, 0, mArrowDrawable.getIntrinsicWidth(),
mArrowDrawable.getIntrinsicHeight());
|
Methods Summary |
---|
private void | cancelAnimator(android.animation.Animator animator)
if (animator != null) {
animator.cancel();
}
| private void | drawArrow(android.graphics.Canvas canvas)
if (mArrowAlpha > 0) {
canvas.save();
canvas.translate(mCenterX, mCenterY);
if (mIsLeft) {
canvas.scale(-1.0f, 1.0f);
}
canvas.translate(- mCircleRadius - mHintChevronPadding
- mArrowDrawable.getIntrinsicWidth() / 2,
- mArrowDrawable.getIntrinsicHeight() / 2);
mArrowDrawable.setAlpha((int) (mArrowAlpha * 255));
mArrowDrawable.draw(canvas);
canvas.restore();
}
| private void | drawBackgroundCircle(android.graphics.Canvas canvas)
if (mCircleRadius > 0) {
updateCircleColor();
canvas.drawCircle(mCenterX, mCenterY, mCircleRadius, mCirclePaint);
}
| public void | finishAnimation(float velocity, java.lang.Runnable mAnimationEndRunnable)
cancelAnimator(mCircleAnimator);
cancelAnimator(mPreviewClipper);
mCircleStartRadius = mCircleRadius;
float maxCircleSize = getMaxCircleSize();
ValueAnimator animatorToRadius = getAnimatorToRadius(maxCircleSize);
mFlingAnimationUtils.applyDismissing(animatorToRadius, mCircleRadius, maxCircleSize,
velocity, maxCircleSize);
animatorToRadius.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mAnimationEndRunnable.run();
}
});
animatorToRadius.start();
setImageAlpha(0, true);
if (mPreviewView != null) {
mPreviewView.setVisibility(View.VISIBLE);
mPreviewClipper = ViewAnimationUtils.createCircularReveal(
mPreviewView, getLeft() + mCenterX, getTop() + mCenterY, mCircleRadius,
maxCircleSize);
mFlingAnimationUtils.applyDismissing(mPreviewClipper, mCircleRadius, maxCircleSize,
velocity, maxCircleSize);
mPreviewClipper.addListener(mClipEndListener);
mPreviewClipper.start();
}
| private android.animation.ValueAnimator | getAnimatorToRadius(float circleRadius)
ValueAnimator animator = ValueAnimator.ofFloat(mCircleRadius, circleRadius);
mCircleAnimator = animator;
mCircleStartValue = mCircleRadius;
mCircleWillBeHidden = circleRadius == 0.0f;
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mCircleRadius = (float) animation.getAnimatedValue();
updateIconColor();
invalidate();
}
});
animator.addListener(mCircleEndListener);
return animator;
| public float | getCircleRadius()
return mCircleRadius;
| private Animator.AnimatorListener | getEndListener(java.lang.Runnable runnable)
return new AnimatorListenerAdapter() {
boolean mCancelled;
@Override
public void onAnimationCancel(Animator animation) {
mCancelled = true;
}
@Override
public void onAnimationEnd(Animator animation) {
if (!mCancelled) {
runnable.run();
}
}
};
| private float | getMaxCircleSize()
getLocationInWindow(mTempPoint);
float rootWidth = getRootView().getWidth();
float width = mTempPoint[0] + mCenterX;
width = Math.max(rootWidth - width, width);
float height = mTempPoint[1] + mCenterY;
return (float) Math.hypot(width, height);
| protected void | onDraw(android.graphics.Canvas canvas)
drawBackgroundCircle(canvas);
drawArrow(canvas);
canvas.save();
canvas.scale(mImageScale, mImageScale, getWidth() / 2, getHeight() / 2);
super.onDraw(canvas);
canvas.restore();
| protected void | onLayout(boolean changed, int left, int top, int right, int bottom)
super.onLayout(changed, left, top, right, bottom);
mCenterX = getWidth() / 2;
mCenterY = getHeight() / 2;
mMaxCircleSize = getMaxCircleSize();
| public boolean | performClick()
if (isClickable()) {
return super.performClick();
} else {
return false;
}
| public void | setCircleRadius(float circleRadius)
setCircleRadius(circleRadius, false, false);
| public void | setCircleRadius(float circleRadius, boolean slowAnimation)
setCircleRadius(circleRadius, slowAnimation, false);
| private void | setCircleRadius(float circleRadius, boolean slowAnimation, boolean noAnimation)
// Check if we need a new animation
boolean radiusHidden = (mCircleAnimator != null && mCircleWillBeHidden)
|| (mCircleAnimator == null && mCircleRadius == 0.0f);
boolean nowHidden = circleRadius == 0.0f;
boolean radiusNeedsAnimation = (radiusHidden != nowHidden) && !noAnimation;
if (!radiusNeedsAnimation) {
if (mCircleAnimator == null) {
mCircleRadius = circleRadius;
updateIconColor();
invalidate();
if (nowHidden) {
if (mPreviewView != null) {
mPreviewView.setVisibility(View.INVISIBLE);
}
}
} else if (!mCircleWillBeHidden) {
// We just update the end value
float diff = circleRadius - mMinBackgroundRadius;
PropertyValuesHolder[] values = mCircleAnimator.getValues();
values[0].setFloatValues(mCircleStartValue + diff, circleRadius);
mCircleAnimator.setCurrentPlayTime(mCircleAnimator.getCurrentPlayTime());
}
} else {
cancelAnimator(mCircleAnimator);
cancelAnimator(mPreviewClipper);
ValueAnimator animator = getAnimatorToRadius(circleRadius);
Interpolator interpolator = circleRadius == 0.0f
? mDisappearInterpolator
: mAppearInterpolator;
animator.setInterpolator(interpolator);
long duration = 250;
if (!slowAnimation) {
float durationFactor = Math.abs(mCircleRadius - circleRadius)
/ (float) mMinBackgroundRadius;
duration = (long) (CIRCLE_APPEAR_DURATION * durationFactor);
duration = Math.min(duration, CIRCLE_DISAPPEAR_MAX_DURATION);
}
animator.setDuration(duration);
animator.start();
if (mPreviewView != null && mPreviewView.getVisibility() == View.VISIBLE) {
mPreviewView.setVisibility(View.VISIBLE);
mPreviewClipper = ViewAnimationUtils.createCircularReveal(
mPreviewView, getLeft() + mCenterX, getTop() + mCenterY, mCircleRadius,
circleRadius);
mPreviewClipper.setInterpolator(interpolator);
mPreviewClipper.setDuration(duration);
mPreviewClipper.addListener(mClipEndListener);
mPreviewClipper.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mPreviewView.setVisibility(View.INVISIBLE);
}
});
mPreviewClipper.start();
}
}
| public void | setCircleRadiusWithoutAnimation(float circleRadius)
cancelAnimator(mCircleAnimator);
setCircleRadius(circleRadius, false ,true);
| public void | setImageAlpha(float alpha, boolean animate)
setImageAlpha(alpha, animate, -1, null, null);
| public void | setImageAlpha(float alpha, boolean animate, long duration, android.view.animation.Interpolator interpolator, java.lang.Runnable runnable)Sets the alpha of the containing image
cancelAnimator(mAlphaAnimator);
int endAlpha = (int) (alpha * 255);
final Drawable background = getBackground();
if (!animate) {
if (background != null) background.mutate().setAlpha(endAlpha);
setImageAlpha(endAlpha);
} else {
int currentAlpha = getImageAlpha();
ValueAnimator animator = ValueAnimator.ofInt(currentAlpha, endAlpha);
mAlphaAnimator = animator;
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int alpha = (int) animation.getAnimatedValue();
if (background != null) background.mutate().setAlpha(alpha);
setImageAlpha(alpha);
}
});
animator.addListener(mAlphaEndListener);
if (interpolator == null) {
interpolator = alpha == 0.0f
? mDisappearInterpolator
: mAppearInterpolator;
}
animator.setInterpolator(interpolator);
if (duration == -1) {
float durationFactor = Math.abs(currentAlpha - endAlpha) / 255f;
durationFactor = Math.min(1.0f, durationFactor);
duration = (long) (NORMAL_ANIMATION_DURATION * durationFactor);
}
animator.setDuration(duration);
if (runnable != null) {
animator.addListener(getEndListener(runnable));
}
animator.start();
}
| public void | setImageScale(float imageScale, boolean animate)
setImageScale(imageScale, animate, -1, null);
| public void | setImageScale(float imageScale, boolean animate, long duration, android.view.animation.Interpolator interpolator)Sets the scale of the containing image
cancelAnimator(mScaleAnimator);
if (!animate) {
mImageScale = imageScale;
invalidate();
} else {
ValueAnimator animator = ValueAnimator.ofFloat(mImageScale, imageScale);
mScaleAnimator = animator;
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mImageScale = (float) animation.getAnimatedValue();
invalidate();
}
});
animator.addListener(mScaleEndListener);
if (interpolator == null) {
interpolator = imageScale == 0.0f
? mDisappearInterpolator
: mAppearInterpolator;
}
animator.setInterpolator(interpolator);
if (duration == -1) {
float durationFactor = Math.abs(mImageScale - imageScale)
/ (1.0f - MIN_ICON_SCALE_AMOUNT);
durationFactor = Math.min(1.0f, durationFactor);
duration = (long) (NORMAL_ANIMATION_DURATION * durationFactor);
}
animator.setDuration(duration);
animator.start();
}
| public void | setIsLeft(boolean left)
mIsLeft = left;
| public void | setPreviewView(android.view.View v)
mPreviewView = v;
if (mPreviewView != null) {
mPreviewView.setVisibility(INVISIBLE);
}
| public void | showArrow(boolean show)
cancelAnimator(mArrowAnimator);
float targetAlpha = show ? 1.0f : 0.0f;
if (mArrowAlpha == targetAlpha) {
return;
}
ValueAnimator animator = ValueAnimator.ofFloat(mArrowAlpha, targetAlpha);
mArrowAnimator = animator;
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mArrowAlpha = (float) animation.getAnimatedValue();
invalidate();
}
});
animator.addListener(mArrowEndListener);
Interpolator interpolator = show
? mAppearInterpolator
: mDisappearInterpolator;
animator.setInterpolator(interpolator);
float durationFactor = Math.abs(mArrowAlpha - targetAlpha);
long duration = (long) (NORMAL_ANIMATION_DURATION * durationFactor);
animator.setDuration(duration);
animator.start();
| private void | updateCircleColor()
float fraction = 0.5f + 0.5f * Math.max(0.0f, Math.min(1.0f,
(mCircleRadius - mMinBackgroundRadius) / (0.5f * mMinBackgroundRadius)));
if (mPreviewView != null) {
float finishingFraction = 1 - Math.max(0, mCircleRadius - mCircleStartRadius)
/ (mMaxCircleSize - mCircleStartRadius);
fraction *= finishingFraction;
}
int color = Color.argb((int) (Color.alpha(mCircleColor) * fraction),
Color.red(mCircleColor),
Color.green(mCircleColor), Color.blue(mCircleColor));
mCirclePaint.setColor(color);
| private void | updateIconColor()
Drawable drawable = getDrawable().mutate();
float alpha = mCircleRadius / mMinBackgroundRadius;
alpha = Math.min(1.0f, alpha);
int color = (int) mColorInterpolator.evaluate(alpha, mNormalColor, mInverseColor);
drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
|
|