Android自定义控件之三点循环缩放效果
本文实例为大家分享了Android自定义控件之三点循环缩放的具体代码,供大家参考,具体内容如下
效果图如上,就是三点循环的变大、变小
package com.example.dotdemo;
import java.util.ArrayList;
import java.util.List;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@SuppressLint("NewApi")
public class DilatingDotsProgressBar extends View {
public static final String TAG = DilatingDotsProgressBar.class.getSimpleName();
public static final double START_DELAY_FACTOR = 0.35;
private static final float DEFAULT_GROWTH_MULTIPLIER = 1.75f;
private static final int MIN_SHOW_TIME = 500; // ms
private static final int MIN_DELAY = 500; // ms
private int mDotColor;
private int mAnimationDuration;
private int mWidthBetweenDotCenters;
private int mNumberDots;
private float mDotRadius;
private float mDotScaleMultiplier;
private float mDotMaxRadius;
private float mHorizontalSpacing;
private long mStartTime = -1;
private boolean mShouldAnimate;
private boolean mDismissed = false;
private ArrayList<DilatingDotDrawable> mDrawables = new ArrayList<DilatingDotDrawable>();
private final List<Animator> mAnimations = new ArrayList<Animator>();
/** delayed runnable to stop the progress */
private final Runnable mDelayedHide = new Runnable() {
@Override
public void run() {
mStartTime = -1;
setVisibility(View.GONE);
stopAnimations();
}
};
/** delayed runnable to start the progress */
private final Runnable mDelayedShow = new Runnable() {
@Override
public void run() {
if (!mDismissed) {
mStartTime = System.currentTimeMillis();
setVisibility(View.VISIBLE);
startAnimations();
}
}
};
public DilatingDotsProgressBar(Context context) {
this(context, null);
}
public DilatingDotsProgressBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DilatingDotsProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
private void init(AttributeSet attrs) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.DilatingDotsProgressBar);
mNumberDots = a.getInt(R.styleable.DilatingDotsProgressBar_dd_numDots, 3);
mDotRadius = a.getDimension(R.styleable.DilatingDotsProgressBar_android_radius, 8);
mDotColor = a.getColor(R.styleable.DilatingDotsProgressBar_android_color, 0xff9c27b0);
mDotScaleMultiplier = a.getFloat(R.styleable.DilatingDotsProgressBar_dd_scaleMultiplier, DEFAULT_GROWTH_MULTIPLIER);
mAnimationDuration = a.getInt(R.styleable.DilatingDotsProgressBar_dd_animationDuration, 300);
mHorizontalSpacing = a.getDimension(R.styleable.DilatingDotsProgressBar_dd_horizontalSpacing, 12);
boolean isShow = a.getBoolean(R.styleable.DilatingDotsProgressBar_dd_show_now, false);
a.recycle();
mShouldAnimate = false;
calculateMaxRadius();
calculateWidthBetweenDotCenters();
initDots();
updateDots();
if (isShow) {
showNow();
}
}
@Override
protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (computeMaxHeight() != h || w != computeMaxWidth()) {
updateDots();
}
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
removeCallbacks();
}
private void removeCallbacks() {
removeCallbacks(mDelayedHide);
removeCallbacks(mDelayedShow);
}
public void reset() {
hideNow();
}
/**
* Hide the progress view if it is visible. The progress view will not be
* hidden until it has been shown for at least a minimum show time. If the
* progress view was not yet visible, cancels showing the progress view.
*/
public void hide() {
hide(MIN_SHOW_TIME);
}
public void hide(int delay) {
mDismissed = true;
removeCallbacks(mDelayedShow);
long diff = System.currentTimeMillis() - mStartTime;
if ((diff >= delay) || (mStartTime == -1)) {
mDelayedHide.run();
} else {
if ((delay - diff) <= 0) {
mDelayedHide.run();
} else {
postDelayed(mDelayedHide, delay - diff);
}
}
}
/**
* Show the progress view after waiting for a minimum delay. If
* during that time, hide() is called, the view is never made visible.
*/
@SuppressWarnings ("unused")
public void show() {
show(MIN_DELAY);
}
@SuppressWarnings ("unused")
public void showNow() {
show(0);
}
@SuppressWarnings ("unused")
public void hideNow() {
hide(0);
}
public void show(int delay) {
mStartTime = -1;
mDismissed = false;
removeCallbacks(mDelayedHide);
if (delay == 0) {
mDelayedShow.run();
} else {
postDelayed(mDelayedShow, delay);
}
}
@Override
protected void onDraw(Canvas canvas) {
if (shouldAnimate()) {
for (DilatingDotDrawable dot : mDrawables) {
dot.draw(canvas);
}
}
}
@Override
protected boolean verifyDrawable(final Drawable who) {
if (shouldAnimate()) {
return mDrawables.contains(who);
}
return super.verifyDrawable(who);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension((int) computeMaxWidth(), (int) computeMaxHeight());
}
private float computeMaxHeight() {
return mDotMaxRadius * 2;
}
private float computeMaxWidth() {
return computeWidth() + ((mDotMaxRadius - mDotRadius) * 2);
}
private float computeWidth() {
return (((mDotRadius * 2) + mHorizontalSpacing) * mDrawables.size()) - mHorizontalSpacing;
}
private void calculateMaxRadius() {
mDotMaxRadius = mDotRadius * mDotScaleMultiplier;
}
private void calculateWidthBetweenDotCenters() {
mWidthBetweenDotCenters = (int) (mDotRadius * 2) + (int) mHorizontalSpacing;
}
@SuppressLint("NewApi")
private void initDots() {
mDrawables.clear();
mAnimations.clear();
Log.i("lcf", "mAnimationDuration = "+mAnimationDuration );
for (int i = 1; i <= mNumberDots; i++) {
final DilatingDotDrawable dot = new DilatingDotDrawable(mDotColor, mDotRadius, mDotMaxRadius);
dot.setCallback(this);
mDrawables.add(dot);
ValueAnimator growAnimator = ObjectAnimator.ofFloat(dot, "radius", mDotRadius, mDotMaxRadius, mDotRadius);
growAnimator.setDuration(mAnimationDuration);
growAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
if (i == mNumberDots) {
growAnimator.addListener(new AnimatorListenerAdapter() {
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public void onAnimationEnd(Animator animation) {
if (shouldAnimate()) {
startAnimations();//注意这个地方,是从新开始启动动画
}
}
});
}
growAnimator.setStartDelay((i - 1) * (int) (START_DELAY_FACTOR * mAnimationDuration));
mAnimations.add(growAnimator);
}
}
@SuppressLint("NewApi")
private void updateDots() {
if (mDotRadius <= 0) {
mDotRadius = getHeight() / 2 / mDotScaleMultiplier;
}
int left = (int) (mDotMaxRadius - mDotRadius);
int right = (int) (left + mDotRadius * 2) + 2;
int top = 0;
int bottom = (int) (mDotMaxRadius * 2) + 2;
for (int i = 0; i < mDrawables.size(); i++) {
final DilatingDotDrawable dot = mDrawables.get(i);
dot.setRadius(mDotRadius);
dot.setBounds(left, top, right, bottom);
ValueAnimator growAnimator = (ValueAnimator) mAnimations.get(i);
growAnimator.setFloatValues(mDotRadius, mDotRadius * mDotScaleMultiplier, mDotRadius);
left += mWidthBetweenDotCenters;
right += mWidthBetweenDotCenters;
}
}
protected void startAnimations() {
mShouldAnimate = true;
for (Animator anim : mAnimations) {
anim.start();
}
}
protected void stopAnimations() {
mShouldAnimate = false;
removeCallbacks();
for (Animator anim : mAnimations) {
anim.cancel();
}
}
protected boolean shouldAnimate() {
return mShouldAnimate;
}
// -------------------------------
// ------ Getters & Setters ------
// -------------------------------
public void setDotRadius(float radius) {
reset();
mDotRadius = radius;
calculateMaxRadius();
calculateWidthBetweenDotCenters();
setupDots();
}
public void setDotSpacing(float horizontalSpacing) {
reset();
mHorizontalSpacing = horizontalSpacing;
calculateWidthBetweenDotCenters();
setupDots();
}
public void setGrowthSpeed(int growthSpeed) {
reset();
mAnimationDuration = growthSpeed;
setupDots();
}
public void setNumberOfDots(int numDots) {
reset();
mNumberDots = numDots;
setupDots();
}
public void setDotScaleMultpiplier(float multplier) {
reset();
mDotScaleMultiplier = multplier;
calculateMaxRadius();
setupDots();
}
public void setDotColor(int color) {
mDotColor = color;
for (DilatingDotDrawable dot : mDrawables) {
dot.setColor(mDotColor);
}
}
private void setupDots() {
initDots();
updateDots();
showNow();
}
public int getDotGrowthSpeed() {
return mAnimationDuration;
}
public float getDotRadius() {
return mDotRadius;
}
public float getHorizontalSpacing() {
return mHorizontalSpacing;
}
public int getNumberOfDots() {
return mNumberDots;
}
public float getDotScaleMultiplier() {
return mDotScaleMultiplier;
}
}
package com.example.dotdemo;
import android.annotation.SuppressLint;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@SuppressLint("Override")
public class extends Drawable {
private static final String TAG = DilatingDotDrawable.class.getSimpleName();
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private float radius;
private float maxRadius;
final Rect mDirtyBounds = new Rect(0, 0, 0, 0);
public DilatingDotDrawable(final int color, final float radius, final float maxRadius) {
mPaint.setColor(color);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeJoin(Paint.Join.ROUND);
this.radius = radius;
setMaxRadius(maxRadius);
}
@Override
public void draw(Canvas canvas) {
final Rect bounds = getBounds();
canvas.drawCircle(bounds.centerX(), bounds.centerY(), radius - 1, mPaint);
}
@Override
public void setAlpha(int alpha) {
if (alpha != mPaint.getAlpha()) {
mPaint.setAlpha(alpha);
invalidateSelf();
}
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
invalidateSelf();
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
public void setColor(int color) {
mPaint.setColor(color);
invalidateSelf();
}
public void setRadius(float radius) {
this.radius = radius;
invalidateSelf();
}
public float getRadius() {
return radius;
}
@Override
public int getIntrinsicWidth() {
return (int) (maxRadius * 2) + 2;
}
@Override
public int getIntrinsicHeight() {
return (int) (maxRadius * 2) + 2;
}
public void setMaxRadius(final float maxRadius) {
this.maxRadius = maxRadius;
mDirtyBounds.bottom = (int) (maxRadius * 2) + 2;
mDirtyBounds.right = (int) (maxRadius * 2) + 2;
}
public Rect getDirtyBounds() {
return mDirtyBounds;
}
@Override
protected void onBoundsChange(final Rect bounds) {
super.onBoundsChange(bounds);
mDirtyBounds.offsetTo(bounds.left, bounds.top);
}
}
源码下载:Android 多点循环缩放
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
以上是 Android自定义控件之三点循环缩放效果 的全部内容, 来源链接: utcz.com/p/241224.html