Android自定义控件之三点循环缩放效果

所属分类: 软件编程 / Android 阅读数: 83
收藏 0 赞 0 分享

本文实例为大家分享了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网络编程之获取网络上的Json数据实例

这篇文章主要介绍了Android网络编程之获取网络上的Json数据实例,本文用完整的代码实例讲解了在Android中读取网络中Json数据的方法,需要的朋友可以参考下
收藏 0 赞 0 分享

Android中的windowSoftInputMode属性详解

这篇文章主要介绍了Android中的windowSoftInputMode属性详解,本文对windowSoftInputMode的9个属性做了详细总结,需要的朋友可以参考下
收藏 0 赞 0 分享

Android网络编程之UDP通信模型实例

这篇文章主要介绍了Android网络编程之UDP通信模型实例,本文给出了服务端代码和客户端代码,需要的朋友可以参考下
收藏 0 赞 0 分享

Android中使用ListView实现漂亮的表格效果

这篇文章主要介绍了Android中使用ListView实现漂亮的表格效果,本文用详细的代码实例创建了一个股票行情表格,需要的朋友可以参考下
收藏 0 赞 0 分享

Android中刷新界面的二种方法

这篇文章主要介绍了Android中刷新界面的二种方法,本文使用Handler、postInvalidate两种方法实现界面刷新,需要的朋友可以参考下
收藏 0 赞 0 分享

Android SDK三种更新失败及其解决方法

这篇文章主要介绍了Android SDK三种更新失败及其解决方法,需要的朋友可以参考下
收藏 0 赞 0 分享

Android学习笔记——Menu介绍(一)

Android3.0(API level 11)开始,Android设备不再需要专门的菜单键。随着这种变化,Android app应该取消对传统6项菜单的依赖。取而代之的是提供anction bar来提供基本的用户功能
收藏 0 赞 0 分享

Android学习笔记——Menu介绍(二)

这次将继续上一篇文章没有讲完的Menu的学习,上下文菜单(Context menu)和弹出菜单(Popup menu)
收藏 0 赞 0 分享

Android学习笔记——Menu介绍(三)

今天继续昨天没有讲完的Menu的学习,主要是Popup Menu的学习,需要的朋友可以参考下
收藏 0 赞 0 分享

Android显示网络图片实例

这篇文章主要介绍了Android显示网络图片的方法,以实例形式展示了Android程序显示网络图片的方法,非常具有实用价值,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多