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 多点循环缩放

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android RecyclerView打造自动循环效果

    先看效果图 主要处理的地方: 1.RecyclerView中Adapter的item个人可以无限轮询. 2.RecyclerView自动滑动 3.手指按下时滑动停止,手指抬起后继续自动滑动 public class AutoPollRecyclerView extends RecyclerView { private static final long TIME_AUTO_POLL = 16; AutoPollTask autoPollTask; private boolean running;

  • Android实现Banner界面广告图片循环轮播(包括实现手动滑动循环)

    前言:经常会看到有一些app的banner界面可以实现循环播放多个广告图片和手动滑动循环.本以为单纯的ViewPager就可以实现这些功能.但是蛋疼的事情来了,ViewPager并不支持循环翻页.所以要实现循环还得需要自己去动手.自己在网上也找了些例子,本博文的Demo是结合自己找到的一些相关例子的基础上去改造,也希望对读者有用. Demo实现的效果图如下: Demo代码: 工程目录如下图: 废话不多说,上代码. 1.主Activity代码如下: package com.stevenhu.and

  • Android实现循环平移动画示例

    实现用一张背景图做循环从左往右平移动画. 1.实现两个animation xml文件,一个起始位置在-100%p ,一个在0%p.设置repeat属性为循环,重复. 复制代码 代码如下: <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolato

  • Android实现图片循环播放的实例方法

    很多时候,我们需要展示在客户端展示图片,而且是动态显示,即不停地自行切换图片.下面我们来看一下具体的实现方法.首先,我们需要在XML...    很多时候,我们需要展示在客户端展示图片,而且是动态显示,即不停地自行切换图片.下面我们来看一下具体的实现方法. 首先,我们需要在XML文件中配置一下将要播放图片的控件(main.xml): 复制代码 代码如下: <?xml version="1.0" encoding="utf-8"?> <LinearL

  • Android 使用ViewPager自动滚动循环轮播效果

    对Android 利用ViewPager实现图片可以左右循环滑动效果,感兴趣的朋友可以直接点击查看内容详情. 主要介绍如何实现ViewPager自动播放,循环滚动的效果及使用.顺便解决ViewPager嵌套(ViewPager inside ViewPager)影响触摸滑动及ViewPager滑动速度设置问题. 先给大家展示下效果图,喜欢的朋友可以下载源码: 1.实现 没有通过ScheduledExecutorService或Timer定期执行某个任务实现,而是简单的通过handler发送消息去

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

    本文实例为大家分享了Android自定义控件之三点循环缩放的具体代码,供大家参考,具体内容如下 效果图如上,就是三点循环的变大.变小 package com.example.dotdemo; import java.util.ArrayList; import java.util.List; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.ani

  • Android自定义控件eBook实现翻书效果实例详解

    本文实例讲述了Android自定义控件eBook实现翻书效果的方法.分享给大家供大家参考,具体如下: 效果图: Book.java文件: package com.book; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.ImageView; public class Book extend

  • 基于Android自定义控件实现刮刮乐效果

    只是简单的实现了效果,界面没怎么做优化,不过那都是次要的啦!!相信大家都迫不及待的想看效果图了吧, 其中主要的彩票视图类和橡皮擦类都是通过代码的方式构建视图,布局文件就一个主activity_main 上代码!! 主activity: package com.guaguale; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.View; imp

  • Android自定义控件简单实现侧滑菜单效果

    侧滑菜单在很多应用中都会见到,最近QQ5.0侧滑还玩了点花样~~对于侧滑菜单,一般大家都会自定义ViewGroup,然后隐藏菜单栏,当手指滑动时,通过Scroller或者不断的改变leftMargin等实现:多少都有点复杂,完成以后还需要对滑动冲突等进行处理~~今天给大家带来一个简单的实现,史上最简单有点夸张,但是的确是我目前遇到过的最简单的一种实现~~~ 1.原理分析 既然是侧滑,无非就是在巴掌大的屏幕,塞入大概两巴掌大的布局,需要滑动可以出现另一个,既然这样,大家为啥不考虑使用Android

  • Android自定义控件之广告条滚动效果

    在一些电子商务网站上经常能够看到一些滚动的广告条,许多软件在首次使用时也有类似的广告条,如图: 其实在github上有实现这种效果的控件,不过这东西做起来也是很简单,我们今天就来看看该怎么做. 先来看看布局文件: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" and

  • Android自定义控件实现按钮滚动选择效果

    本文实例为大家分享了Android实现按钮滚动选择效果的具体代码,供大家参考,具体内容如下 效果图 代码实现 package com.demo.ui.view; import android.annotation.TargetApi; import android.content.Context; import android.os.Build; import android.os.Handler; import android.support.v4.content.ContextCompat;

  • Android自定义控件实现下拉刷新效果

    app开发中下拉刷新是最常接触到的一个功能,也有很多开源的框架,封装的非常棒.前段时间了解了一下ViewDragHelper,遂用它实现了下拉刷新的功能. 大概和我之前的ViewDragHelper之拖动加载(类似淘宝)这篇代码类似.只是做了相关改动.具体的可以看一下那篇博文了解一下用到的ViewDragHelper的一些知识点.该界面主要是一个LinearLayout,上面的下拉刷新是一个textview(用TV代替),当然这个可以定制,在此只是用一个textview代替,实现简单的功能,下面

  • Android自定义控件实现球赛比分条效果

    本文实例为大家分享了Android实现球赛比分条效果的具体代码,供大家参考,具体内容如下 效果图如下所示: 该控件需要输入两个参数,左边的得分数和右边的的分数 然后根据两边的得分的比例绘制中间的比分条 首先将控件的宽度平均分配为10分,第一份和最后一份分别绘制左边的比分数字和右边的比分数字 中间的8分宽度绘制比分条 根据左右两个比分所占的比例,绘制两个两条首位相连的线段即可 完整代码如下: public class CustomScoreBar extends View { private Co

  • Android自定义控件实现温度旋转按钮效果

    首先看下效果图 温度旋转按钮 实现思路 初始化一些参数 绘制刻度盘 绘制刻度盘下的圆弧 绘制标题与温度标识 绘制旋转按钮 绘制温度 处理滑动事件 提供一些接口方法 实现方法 初始化一些参数 public class TempControlView extends View { // 控件宽 private int width; // 控件高 private int height; // 刻度盘半径 private int dialRadius; // 圆弧半径 private int arcRa

  • Android仿QQ好友详情页下拉顶部图片缩放效果

    本文实例为大家分享了Android下拉顶部图片缩放效果展示的具体代码,供大家参考,具体内容如下 效果图 效果分析 1 向下滑动,头部的图片随着手指滑动不断变大 2 向上滑动,不断的向上移动图片,直到图片不可见 3 当顶部图片不可见时,向上滑动,滑动ListView 实现思路 1 由于这个View分上下两部分,垂直排列,可以通过继承LinearLayout实现::自定义一个DragImageView,该View继承LinearLayout public DragImageView(Context

随机推荐