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

 更新时间:2018年10月08日 08:44:29   作者:Luo446718254  
这篇文章主要为大家详细介绍了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 Studio 格式化快捷键和QQ 锁键盘快捷键冲突问题

    解决Android Studio 格式化快捷键和QQ 锁键盘快捷键冲突问题

    每次打开qq使用android studio格式化的快捷键Ctrl + Alt +L时,总是出现qq锁键盘提示,怎么回事呢?下面小编给大家带来了android studio格式化的快捷键和qq快捷键之间的冲突的处理方法,需要的朋友参考下吧
    2017-12-12
  • Android开发自学笔记(三):APP布局上

    Android开发自学笔记(三):APP布局上

    这篇文章主要介绍了Android开发自学笔记(三):APP布局上,本文讲解了添加ViewGroup、添加ViewGroup、定义string内容、添加Button、运行程序查看效果等内容,需要的朋友可以参考下
    2015-04-04
  • Kotlin新手基础学习之Elvis操作符

    Kotlin新手基础学习之Elvis操作符

    Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,被称之为 Android 世界的Swift,由 JetBrains 设计开发并开源,下面这篇文章主要给大家介绍了关于Kotlin新手基础学习之Elvis操作符的相关资料,需要的朋友可以参考下。
    2017-12-12
  • Android实现点击两次BACK键退出应用

    Android实现点击两次BACK键退出应用

    这篇文章主要为大家详细介绍了Android实现点击两次BACK键退出应用的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-09-09
  • Android 照片选择区域功能实现示例

    Android 照片选择区域功能实现示例

    这篇文章主要介绍了Android 照片选择区域功能实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • Libgdx解决部分Android机型锁屏崩溃的方法

    Libgdx解决部分Android机型锁屏崩溃的方法

    今天小编就为大家分享一篇关于Libgdx解决部分Android机型锁屏崩溃的方法,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-10-10
  • Android实现自动挂断电话功能的示例代码

    Android实现自动挂断电话功能的示例代码

    在开发Android应用时,有时会遇到需要实现自动挂断电话的需求,本文将详细介绍一下如何在Android中实现自动挂断电话的功能,需要的小伙伴可以参考一下
    2025-04-04
  • Android MIUI通知类短信权限的坑

    Android MIUI通知类短信权限的坑

    本篇文章主要介绍了Android MIUI通知类短信权限的坑,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03
  • Android RecyclerView设置下拉刷新的实现方法

    Android RecyclerView设置下拉刷新的实现方法

    这篇文章主要介绍了Android RecyclerView设置下拉刷新的实现方法,希望通过本文通过SwipeRefreshLayout方式实现下拉刷新,需要的朋友可以参考下
    2017-10-10
  • Android小米推送简单使用方法

    Android小米推送简单使用方法

    这篇文章主要为大家详细介绍了Android小米推送简单使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-01-01

最新评论